戯言

つらつらと気づいたことを書いていきます。人狼とか。

java.util.ConcurrentModificationExceptionの原因と対策


java.util.Concurrent Modification Exceptionの原因と対策

ArrayListなどの非同期クラスのインスタンスが、別スレッドから変更されると、「勝手に変更されたよ?」ってことでjava.util.ConcurrentModificationExceptionが発生する。Webアプリケーションなどで、複数のスレッドから同時にListを触られるとよく出る例外ですね。

これの対策を調べていたら、Collections.synchronizedListという便利なものが標準で用意されていて、いちいちListを使っている箇所を全てsynchronized句で同期をとるなんて面倒なことをしなくても、対象インスタンスの生成時に、このインスタンスは共有するので同期化してくれるらしい。

こんな感じで書けば、対象のインスタンスを同期化してくれる。
private List<ChatMessage> messages
  = Collections.synchronizedList(new ArrayList<ChatMessage>());

これは便利だと思い、早速コードを変更して、しばらく様子を見ていたら、またあのjava.util.ConcurrentModificationExceptionが稀に発生している。1日に1回くらい。

また調べる。

どうやら、Collections.synchronizedListで、同期をしてくれるのは、message.add()メソッドやmessage.remove()メソッドなどを呼び出す時だけで、Iteratorを使ってListにアクセスする場合は, synchronized修飾子を使わなければならないようだ。

add/removeメソッドなどの呼び出し時に、内部的にsynchronizedブロックで同期化してくれるだけなので、当然と言えば当然なのですが。

というわけで、forループ内でListを参照しているところがあったので、ここを明示的にsynchronizedブロックで囲みました。また、これで様子を見よう・・・。
関連記事

管理者にだけ表示を許可する