2013-06-12 3 views
0

문제의 배경 : 다양한 클라이언트에게 서비스 변경 사항을 알리는 책임이있는 클래스가 있습니다. 따라서 클래스에는 여러 청취자의 HashMap이 있고 필요한 경우 해당 HashMaps를 반복하여 메서드를 호출합니다 (해당 HashMaps에서 청취자를 추가/제거하는 메서드도 있음). 문제는 반복되는 동안 특정 리스너를 제거해야한다는 것입니다 ... 그리고 루프 외부에서 remove (...) 메서드를 호출 할 수 있어야합니다.동일한 스레드에서 반복 및 제거가 모두 발생합니다. 클래스의 예 :반복자를 사용하지 않고 HashMap에서 항목을 동시에 수정/제거

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(); 
    }} 

내가 (...) 제거 전화를 원하는 방식으로 (그 실패 방법) :

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 

이 작업을 수행하기 위해 어떤 트릭이 있습니까?

답변

1

귀하의 문제는 ConcurrentHashMap를 사용하기위한 후보입니다. 지도 정의를 ConcurrentHashMap으로 바꿉니다.

Map<Listener, Boolean> listeners = new ConcurrentHashMap<Listener, Boolean>(); 
+0

네, 작동합니다. 그건 그렇고, 언제 제거가 일어나고 있습니까? 전화가 오면 ** ** a ** 항목이 제거되었는지 확인할 수 있습니까? –

+0

제거는 실시간으로 발생하지만 컬렉션의 스냅 샷에서 반복이 발생합니다. @finejustice가 공유하는 문서를 읽으십시오. 도움이 될거야 :) – vineet