Java同時集合操作におけるロックへの応用.


以下、リスト結合を例として、
まず、次のコードを見てみましょう.
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()の2つのコアを持つ方法で、読み書きロックと書き込みロックを取得します.リードロックを取得するには、ライトロックがロックされていないことが前提です.書き込みロックを取得する前提は、読み取りロックがロックされていないことです.つまり、読むときにデータを書いたり修正したりする人がいないことを保証します.データを書いたり修正したりするとき、データを読んでいる人はいません.私たちが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
なぜt 3の印刷がないのか疑問に思うかもしれません.リードロックが解放されると、すぐにライトロックに占有され、ライトロックのスレッドが集合を空にしたため、スレッド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
リードロックは異なるスレッドでは反発しないことがわかります.はい、ここまでご紹介します.