かとじゅんの技術日誌

技術の話をするところ

同期化不要なCopyOnWriteArrayListを使え

java.util.concurrent
クラス CopyOnWriteArrayList

どんなクラスかというと、リストの変更操作(addやremoveなど)で、ConcurrentModificationExceptionをスローしないことが保証されるArrayListクラスです。
たとえば、通常のArrayListでは、リストのイテレート中にそのリストの要素を削除した場合、ConcurrentModificationExceptionがスローされます。

List<Hoge> hogeList = new ArrayList<Hoge>();
for(Hoge h : hogeList){
    System.out.println(h);
    hogeList.remove(h);// ConcurrentModificationException
}

こういうことが発生しないようにプログラマはリストに対する変更操作をリスト走査中に行わないようにするわけですが、たいていの場合でコンカレントコレクションでその苦労をしないで済みます。

CopyOnWriteArrayListでは、リストに対するすべての変更操作が内部リストの"コピー"に対して行われるのでこのようなことが発生しません。イテレータは常にスナップショットな内部リストに対するものとなります。
また、複数のスレッドからaddやremoveされる場合であっても、わざわざ同期化(synchronized)する必要がありません。変更対象が、リストのコピーだからです。パフォーマンスはよくありませんが、変更操作より走査することが多い場合にかなり有用だと思います。
new ArrayList()ではなく、new CopyOnWriteArrayList()すればよいだけ。

List<Hoge> hogeList = new CopyOnWriteArrayList<Hoge>();

ということで、スレッドセーフなリストが欲しい場合は、素直にCopyOnWriteArrayListを使うとよいと思います。