- PR -

ConcurrentModificationException

1
投稿者投稿内容
Kira
ぬし
会議室デビュー日: 2004/10/30
投稿数: 252
投稿日時: 2005-01-05 15:16
500個あるLinkedHashMapのキーに対してすべてremoveを行うと
100個めくらいでjava.util.ConcurrentModificationException
が発生してしまいます。

内容を見てみると同期がとれていないということだったのですが、
特にそれらしい部分がみあたりません。
他に理由はあるのでしょうか。
LinkedHashMapに対してremoveするのがまずいのでしょうか。
vincent
大ベテラン
会議室デビュー日: 2004/07/09
投稿数: 142
投稿日時: 2005-01-05 23:52
どのような状況下でそうなっているか解らないので何ともいえませんが
LinkedHashMapの実装は同期化されていません。
引用:

複数のスレッドが同時にリンクハッシュセットにアクセスし、
それらのスレッドの少なくとも 1 つが構造的にマップを変更する場合には、
外部で同期をとる必要があります。(Javadoc)


マップの変更中に他のスレッドから読み取りや変更を行っていませんか?
また、synchronizedを使った場合はどうなりますか?

synchronized(map){
 map.remove(key);
}

あと、すべてのキーに対してremoveするのであれば、
clear()を使ったほうが良いと思います。
pascal
常連さん
会議室デビュー日: 2004/04/29
投稿数: 29
お住まい・勤務地: 神奈川県
投稿日時: 2005-01-06 00:08
例えば、

Map map = Collections.synchronizedMap(
new LinkedHashMap(500));
       /* 何か処理をする */
Object[] keys = map.keySet().toArray();
for ( int i = 0 ; i < keys.length ; i++) {
key = (Integer)keys[i];
map.remove(key);
}

で駄目ですか?
必ず全部消すのなら、clearが良いとは思いますけど、
もし、「消すべきマッピングはいくつかあるか分からないが、場合により、全部消すことがある」ということでしたら、clearでは解決しませんよね。
coasm
大ベテラン
会議室デビュー日: 2001/11/26
投稿数: 237
投稿日時: 2005-01-07 00:36
APIドキュメントに(いささか解りにくい表現で)書いてある通り、
ConcurrentModificationException という例外は、Iteratorを使用している最中に、
元になるCollectionやMapを変更した際にthrowされます。

原因は大きく分けて2種類あります。

(1) 単にIteratorの使い方が間違っている。
コード:
Map map = ...
for(Iterator i = map.keySet().itertor(); i.hasNext(); ){
    Object key = i.next();
    if( is削除すべき(key) ){
        map.remove(key);    // <--やってはいけない。
    }
}


この例の場合なら、map.remove(key) ではなくて i.remove() とすればOKです。

(もちろん、全要素をremoveしたいのであれば、map.clear()の方が適切ですが)

(2) スレッド間の排他が抜けている、または適切でない。
この場合は、単にsynchronizedMapを使うだけではダメで、
Iteratorを使用している全期間を排他する必要がある点に要注意です。

コード:
synchronized(map){
    for(Iterator i = map.keySet().itertor(); i.hasNext(); ){
       ......
    }
}

1

スキルアップ/キャリアアップ(JOB@IT)