[Proxool-developer] CodeReview - AbstractListenerContainer
UNMAINTAINED!
Brought to you by:
billhorsman
From: Bertrand R. <ber...@mo...> - 2004-03-11 23:24:58
|
I had a look at the AbstractListenerContainer... and found it much = complex for what it is supposed to do. =20 Let's recap the (supposed) requirements: - fast access to the list of registered listeners - frequent (read); - must support concurrency; - add/remove can be slower and are less frequent (update) =20 =20 The following implementation makes use of an object array to store the reference to registered listeners. Every time add/remove is called, a new array is created with the new = state - the original is *not modified* but *replaced* by a new one. This = behavior is important since it guarantees that once you got the array, you know it = will never been modified while you play with it. Thanks to this trick, no = need for read/write locks and a fast access to the list ;-) =20 The only precaution now is to make sure that only one thread can access add/remove at a time. This code is protected by synchronized statement - which is not a penality since modifications are not frequent. =20 =20 Classes extending this container can get access to the list of = registered listener by calling the protected getListeners() method that returns a reference to the array. It is now enough to iterate through the array with a simple for loop. = That's another benefit: no need to construct an iterator every time we have to deliver an event... =20 =20 All this is definitly less expensive than the current implementation = that makes heavy use of synchronized statements :( =20 =20 The (new) code is below. Feel free to send any comments :) =20 public abstract class AbstractFastListenerContainer implements ListenerContainerIF=20 { static final Log LOG =3D LogFactory.getLog(AbstractFastListenerContainer.class); =20 private Object[] listeners =3D EMPTY_LISTENERS; private static final Object[] EMPTY_LISTENERS =3D new Object[]{}; /** * @see ListenerContainerIF#addListener(Object) */ public synchronized void addListener(Object listener)=20 { // create a new array Object[] newListeners =3D new Object[listeners.length]; =20 // copy listeners currently registered System.arraycopy(listeners, 0, newListeners, 0, = listeners.length); =20 // add the new one newListeners[listeners.length] =3D listener; =20 // commit changes listeners =3D newListeners; } =20 =20 /** * @see ListenerContainerIF#removeListener(Object) */ public synchronized boolean removeListener(Object listener)=20 { // find listener to remove in the list int index=3D-1; for(int i=3D0; i<listeners.length; i++) { if( listeners[i]=3D=3Dlistener ) { index =3D i; break; } } =20 // not found ? if( index=3D=3D-1 ) return false; =20 // create a new array of the right size Object[] newListeners =3D new Object[listeners.length-1]; =20 // copy registered listeners minus the one to remove if( index > 0 ) System.arraycopy(listeners, 0, newListeners, 0, index); =20 if( index < listeners.length-1 ) System.arraycopy(listeners, index+1, newListeners, index, listeners.length-index-1); =20 // commit listeners =3D newListeners; return true; } =20 /** * Get a reference to the array containing registered listeners */ protected Object[] getListeners() { return listeners; } /** * @see ListenerContainerIF#isEmpty() */ public boolean isEmpty() { return listeners.length=3D=3D0; } } =20 =20 |