首页 > 代码库 > Java并发集合操作中对锁的应用。

Java并发集合操作中对锁的应用。

下面以List结合为例子,

先来看以下代码:

public static ArrayList<String>datas=new ArrayList<String>();
//初始化数据
	public static void initData(){
		for(int i=0;i<20;i++){
			datas.add(""+i);
		}
	}
	
//线程1,读取集合的数据	
	public static  Thread thread1=new Thread(){
		public void run() {
			//int size=datas.size();
			for(String data:datas){
				System.out.println(data);
			}
		};
	};
//线程2,删除集合的数据
	private static Thread thread2=new Thread(){
		public void run() {
			int size=datas.size();
			for(int i=0;i<size;i++){
				datas.remove(0);
				System.out.println("remove");
			}
		};
	};
//启动程序
        public static void main(String[] args) {
		initData();
		thread1.start();
		thread2.start();
	}



这样子运行的话,肯定会出一个异常。下面请看执行的结果
remove
remove
1
remove
remove
remove
remove
remove
remove
Exception in thread "Thread-0" remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)


在现实编程环境中,经常会遇到既需要遍历集合,又需要在另一个线程中删除集合。那么怎么解决呢?

下面就来解决这个问题,我们用到了位于java.util.concurrent.locks包里面的ReentrantReadWriteLock;

简称读写锁,它有两个核心的方法,分别是readLock()和writeLock(),即获取读锁和写锁。获取读锁的前提是写锁没有锁住。获取写锁的前提是读锁没有锁住。也就是保证在读的时候就没有人在写数据或者修改数据。在写数据或者修改数据的时候就没有人在读数据。就好像我们编辑word文档一样,在编辑状态,就不允许移动,复制。根据这个原理,我们接下来改进代码如下:

public static final ReadWriteLock lock = new ReentrantReadWriteLock(false);
	
	public static ArrayList<String>datas=new ArrayList<String>();
	public static void initData(){
		for(int i=0;i<20;i++){
			datas.add(""+i);
		}
	}
	
	
	public static  Thread thread1=new Thread(){
		public void run() {
			lock.readLock().lock();
			for(String data:datas){
				System.out.println("t1  "+data);
			}
			lock.readLock().unlock();
		};
	};
	public static  Thread thread3=new Thread(){
		public void run() {
			lock.readLock().lock();
			for(String data:datas){
				System.out.println("t3  "+data);
			}
			lock.readLock().unlock();
		};
	};

	
	private static Thread thread2=new Thread(){
		public void run() {
			int size=datas.size();
			lock.writeLock().lock();
			for(int i=0;i<size;i++){
				datas.remove(0);
				System.out.println("remove");
			}
			lock.writeLock().unlock();
		};
	};
	
	public static void main(String[] args) {
		initData();
		thread1.start();
		thread2.start();
		thread3.start();
	}



这时候程序执行结果是:

t1  0
t1  1
t1  2
t1  3
t1  4
t1  5
t1  6
t1  7
t1  8
t1  9
t1  10
t1  11
t1  12
t1  13
t1  14
t1  15
t1  16
t1  17
t1  18
t1  19
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove


大家可能疑惑为啥没有t3的打印呢?因为读锁在释放之后,立马就被写锁占用了,写锁的线程把集合清空了,所以当轮到线程3的时候就没有数据了,多试几次,会发现还有一种执行结果就是全部都是remove。没有任何打印,这是因为先执行了线程2的缘故。如果我们按照这样的顺序执行,又会不同:
public static void main(String[] args) {
		initData();
		thread1.start();
		thread3.start();
		thread2.start();
	}



t3  0
t1  0
t3  1
t1  1
t3  2
t1  2
t3  3
t1  3
t3  4
t1  4
t3  5
t1  5
t3  6
t1  6
t3  7
t1  7
t3  8
t1  8
t3  9
t1  9
t3  10
t1  10
t3  11
t1  11
t3  12
t1  12
t3  13
t1  13
t3  14
t1  14
t3  15
t1  15
t1  16
t1  17
t3  16
t1  18
t1  19
t3  17
t3  18
t3  19
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove

可以看到读锁在不同的线程中是不排斥的。好的,就为大家介绍到这里。

Java并发集合操作中对锁的应用。