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が発生しなくなりました。