0

問題の背景: サービスの変更についてさまざまなクライアントに通知するクラスがあります。そのため、クラスにリスナーの HashMap がいくつかあり、必要に応じてこれらの HashMap を反復してメソッドを呼び出します (これらの HashMap からリスナーを追加/削除するメソッドもあります)。問題は、反復中に特定のリスナーを削除する必要があることが多いことです...そして、ループの外側から remove(...) メソッドを呼び出せるようにする必要があります。 反復と削除の両方が同じスレッドで行われています。クラスの例:

class SomeClass {
    Map<Listener, Boolean> listeners = new HashMap<Listener, Boolean>();

    void add(Listener listener) {
        listeners.put(listener, true);
    }

    void remove(Listener listener) {
        listeners.remove(listener);
    }

    void notifyListeners() {
        Iterator<Map.Entry<Listener, Boolean>> it = listeners.entrySet().iterator();
        while (it.hasNext()) {
            it.next().getKey().onDo();
        }
    }

    static interface Listener{
        void onDo();
    }}

そして、remove(...) を呼び出したい方法 (およびそれが失敗する方法):

final SomeClass someClass = new SomeClass();

    Listener a = new Listener(){
        @Override
        public void onDo() {
            someClass.remove(this);
        }
    };

    Listener b = new Listener(){
        @Override
        public void onDo() {
            someClass.remove(this);
        }
    };

    Listener c = new Listener(){
        @Override
        public void onDo() {
            someClass.remove(this);
        }
    };

    someClass.add(a);
    someClass.add(b);
    someClass.add(c);

    someClass.notifyListeners();
    // java.util.ConcurrentModificationException

これを行うためのトリックはありますか?

4

2 に答える 2

2

ConcurrentHashMap を試しましたか?

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html

于 2013-06-12T18:37:41.223 に答える
1

あなたの問題は を使用する候補ですConcurrentHashMap。マップ定義を次のように置き換えるだけですConcurrentHashMap

Map<Listener, Boolean> listeners = new ConcurrentHashMap<Listener, Boolean>();
于 2013-06-12T18:42:50.033 に答える