'Is Apache EventListenerSupport thread safe?
Summary
The org.apache.commons.lang3.event.EventListenerSupport
is used in order to fire when some class performs a certain operation and wants to inform all listeners about it.
This class is however accessed by multiple threads and is already forced to synchronize on other lists it processes, so that a ConcurrentModificationException
is avoided.
Different threads are responsible for adding, removing and firing events. The functions for this purpose look like this:
public void addListener( MyListener listener )
{
myEventSupport.addListener( listener );
}
public void removeListener( MyListener listener )
{
myEventSupport.removeListener( listener );
}
public void someEvent()
{
// do other stuff
myEventSupport.fire().updateIssued();
}
Since I already ran into concurrency issues with the class I anticipate simultaneous access to the EventListenerSupport myEventSupport
. This is both reading and writing access.
Question
I was unable to find anything on synchronization and thread-safety in the Apache documentation: https://commons.apache.org/proper/commons-lang/javadocs/api-3.8/org/apache/commons/lang3/event/EventListenerSupport.html
However I did find this comment in the description of the .class
file itself:
public class EventListenerSupport<L> implements Serializable {
// [...]
/**
* The list used to hold the registered listeners. This list is
* intentionally a thread-safe copy-on-write-array so that traversals over
* the list of listeners will be atomic.
*/
private List<L> listeners = new CopyOnWriteArrayList<>();
// [...]
}
Is it therefore safe to assume, concurrent access to addListener
, removeListener
, as well as fire
is handled by EventListenerSupport
?
Solution 1:[1]
I am no expert in this but for me it seems like the following:
The call to fire
uses the internal proxy to ultimately call the following loop:
public Object invoke(final Object unusedProxy, final Method method, final Object[] args) throws Throwable {
for (final L listener : listeners) {
method.invoke(listener, args);
}
return null;
}
And the CopyOnWriteArrayList
used is documented as follows:
A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.
This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads.
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
So I basically see the above iteration and see the iterate safely in the documentation.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |