Reputation: 1234
Some background to the problem: I have a class which is responsible for informing various clients about changes in service. So it the class has several HashMaps of listeners and calls their methods by iterating those HashMaps when needed (it also has methods to add/remove listeners from those HashMaps). The problem is that often I need remove certain listeners while they are being iterated... and I need to be able to call remove(...) method from outside the loop. Both iterating and removing are happening on the same thread. Example of the class:
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();
}}
And the way I want to call remove(...) (and how that fails):
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
Is there any trick to do this?
Upvotes: 0
Views: 905
Reputation: 336
Your problem is candidate for using ConcurrentHashMap
. Just replace your map definition to ConcurrentHashMap
Map<Listener, Boolean> listeners = new ConcurrentHashMap<Listener, Boolean>();
Upvotes: 1
Reputation: 413
Did you tried ConcurrentHashMap?
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html
Upvotes: 2