2

次のコードの場合、複数のスレッドで実行します。

private static final Map<String, keyinfo> mapKeys = new ConcurrentHashMap<String, keyinfo>();

private static void purgeOldKeys() {
    for (Map.Entry<String, keyinfo> key : mapKeys.entrySet()) {
        if(key.getValue().createTime + keyCacheTime < getCurrentDBTime())
            mapKeys.remove(key);
    }
}

シンクロナイザーを回避できますか?

または、すでに削除された要素を削除することは、JavaDoc に従って定義されていないため、シンクロナイザは引き続き必要ですか?

4

2 に答える 2

5

一般に、コレクションから削除するIterator場合、怠惰な「foreach」の概念の代わりに完全なAPIを使用する方がはるかにクリーンです(そして高速です!) 。

iterator.remove();イテレータを無効にしません。そしてそれはそれがあった位置を知っています。次のパターンを使用します。

for (Iterator<> iter = map.entrySet().iterator(); iter.hasNext(); ) {
    Map.Entry<> entry = iter.next();
    if (testRemoval(entry))
        iter.remove(); // <----- remove using the iterator position!
}

オブジェクトを再度検索する必要がないため、高速です。イテレータはオブジェクトが削除されたことを認識しているため、より堅牢です。多くのコレクションでは、同時変更のため、上記のコードは「高速失敗」します。

于 2013-01-29T15:03:32.337 に答える
4

1) このコードにはバグがあるため、何も削除できませんmapKeys.remove(key);- コード内のキーは実際には Map.Entry です。そのはず

for (Map.Entry<String, keyinfo> e : map.entrySet()) {
    if (e.getValue().createTime + keyCacheTime < getCurrentDBTime())
            map.remove(e.getKey());
    }
}

2) ConcurrentHashMap を反復処理しながらエントリを削除するのは安全です。 ConcurrentHashMap.entrySet API

The view's iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException

そして、このテストはそれを確認します

    Map<String, String> map = new ConcurrentHashMap<String, String>();
    map.put("1", "2");
    map.put("2", "2");
    map.put("3", "3");
    for (String k : map.keySet()) {
        map.remove(k);
    }
    System.out.println(map);

版画

{}
于 2013-01-29T15:11:40.790 に答える