Listeners, CopyOnWriteArrayList and removals
A common suggestion to avoid ConcurrentModificationExceptions when iterating through listeners is to use a CopyOnWriteArrayList.
But isn't there a possible issue that you will then call a listener that just de-registered? If the listening object wasn't expecting this, it could cause problems.
What is the usual solution to this? Require any listener objects that de-register to keep a volatile state variable indicating their registration status, and to ignore the event if they aren't registered?
Re: Listeners, CopyOnWriteArrayList and removals
Can you post some code that more clearly defines this? From what I gathered it seems you are talking about the following scenario: you have a List which contains an interface, iterating over that list to call the interface methods, then what may happen if an entry in the list is removed during iteration. To avoid synchronization issues in this scenario you can place the list in a synchronize block - synchronizing on the List object...any removal from the list in another thread will then have to wait until the lock is released (the synchronized block ends)
Code java:
synchronize(list){
for ( int i = 0; i < list.size(); i++ ){
list.get(i).....
}
}
Re: Listeners, CopyOnWriteArrayList and removals
Thanks for the response. I found another thread discussing the same thing which may provide some background:
https://www.ibm.com/developerworks/f...4954�
Your response is on the right track. I have an object that needs to inform others when it changes. It allows others to register a listener. E.g. object is a model, various other objects need to know when the model changes. The listeners are stored in some collection (my suggestion was a CopyOnWriteArrayList, your response used a List). When a change occurs, the object must call each listener.
If you just store the listeners in a list, and use an iterator to go through them, you are at risk of getting a Concurrent ModificationException if either another thread or one of the listeners itself either add or remove a listener. I can see a few ways to prevent this.
1) synchronize on the list (call this lock A) when doing an add, remove or looping through the list (as your response suggested).This introduces the risk of deadlock, e.g.
a) thread A has lock A and is looping through the listeners
b) thread B has lock B, tries to add/remove a listener and therefore blocks on lock A
c) a listener (running in thread A) tries to acquire lock B
2) use a CopyOnWriteArrayList to store the listeners. This introduces the problem of my original post.
a) thread A is looping through the listeners (no lock involved)
b) thread B (or code called from the listener) removes a listener that hasn't yet been called.
c) thread A is still using an old copy of the list of listeners (since the COWAL uses a snapshot iterator), so it then calls the listener that was already removed.
I'm coming to the conclusion you can't make this bullet proof without placing some restrictions on the listeners. For example, the listener can't do anything that will add/remove a listener. Or the listener must be robust against being called after it was removed.