talosのプログラミング教室

Java Gold合格への道 ~並行処理・並行コレクション~

スポンサーリンク

こんにちは。たろすです。

今回は並行処理における並行コレクションについて説明します。

コレクションと並行コレクションの違い

コレクションと言えばArrayListやHashMapなどがあります。

これらはスレッド・セーフではなく、並行処理においてConcurrentModificationExceptionが発生する可能性があります。

一方で並行コレクションはスレッド・セーフのためこの例外は発生しません。

並行コレクションにはCopyOnWriteArrayListやConcurrentMapなどがあります。

試しにCopyOnWriteArrayListを使ってその違いを確認してみましょう。

ArrayListでの実装

public class Main {
	public static void main(String[] args) {

		List<Integer> list = new ArrayList<>();

		for (int i = 0; i < 1000; i++) {
			list.add(i);
		}

		Thread t1 = new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 1000; i++) {
					list.remove(0);
				}
			}
		});

		Thread t2 = new Thread(new Runnable() {
			public void run() {
				for (Integer num : list) {
					System.out.println(num);
				}
			}
		});

		t1.start();
		t2.start();
	}
}
Exception in thread "Thread-1" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at collection.Main$2.run(Main.java:27)
	at java.lang.Thread.run(Thread.java:748)

上記のコードは0~999までの数値をArrayListに格納し、先頭から削除すると同時に走査しています。

当然走査している最中にArrayListが変更されてしまうので、ConcurrentModificationExceptionが発生します。

CopyOnWriteArrayListでの実装

これをConcurrentModificationExceptionが発生しないようにCopyOnWriteArrayListで実装するとどうなるかというと、

public class Main {
	public static void main(String[] args) {

		List<Integer> list = new CopyOnWriteArrayList<>();

		for (int i = 0; i < 1000; i++) {
			list.add(i);
		}

		Thread t1 = new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 1000; i++) {
					list.remove(0);
				}
			}
		});

		Thread t2 = new Thread(new Runnable() {
			public void run() {
				for (Integer num : list) {
					System.out.println(num);
				}
			}
		});

		t1.start();
		t2.start();
	}
}
76
77

省略

998
999

Listの定義をArrayListからCopyOnWriteArrayListに変えただけです。

CopyOnWriteArrayListを使うことによりConcurrentModificationExceptionが発生しなくなりました。

おわりに

今回は並行処理における並行コレクションについて説明しました。