Thread: [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 |
From:
<chr...@em...> - 2004-03-13 14:40:31
|
Good :) Thats my piece of verbose code. Have Bill given you commit rights yet? If so feel free to replace it with what you suggest. CHR Bertrand Renuart wrote: > I had a look at the AbstractListenerContainer... and found it much > complex for what it is supposed to do. > > 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) > > > 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 ;-) > > 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. > > > 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... > > > All this is definitly less expensive than the current implementation > that makes heavy use of synchronized statements :( > > > The (new) code is below. > Feel free to send any comments :) > > > public abstract class AbstractFastListenerContainer implements > ListenerContainerIF > { > static final Log LOG = > LogFactory.getLog(AbstractFastListenerContainer.class); > > private Object[] listeners = EMPTY_LISTENERS; > private static final Object[] EMPTY_LISTENERS = new Object[]{}; > > /** > * @see ListenerContainerIF#addListener(Object) > */ > public synchronized void addListener(Object listener) > { > // create a new array > Object[] newListeners = new Object[listeners.length]; > > // copy listeners currently registered > System.arraycopy(listeners, 0, newListeners, 0, listeners.length); > > // add the new one > newListeners[listeners.length] = listener; > > // commit changes > listeners = newListeners; > } > > > /** > * @see ListenerContainerIF#removeListener(Object) > */ > public synchronized boolean removeListener(Object listener) > { > // find listener to remove in the list > int index=-1; > for(int i=0; i<listeners.length; i++) { > if( listeners[i]==listener ) { > index = i; > break; > } > } > > // not found ? > if( index==-1 ) > return false; > > // create a new array of the right size > Object[] newListeners = new Object[listeners.length-1]; > > // copy registered listeners minus the one to remove > if( index > 0 ) > System.arraycopy(listeners, 0, newListeners, 0, index); > > if( index < listeners.length-1 ) > System.arraycopy(listeners, index+1, newListeners, index, > listeners.length-index-1); > > // commit > listeners = newListeners; > return true; > } > > > /** > * Get a reference to the array containing registered listeners > */ > protected Object[] getListeners() { > return listeners; > } > > > /** > * @see ListenerContainerIF#isEmpty() > */ > public boolean isEmpty() { > return listeners.length==0; > } > } > > > > > |
From: Bertrand R. <ber...@mo...> - 2004-03-13 23:59:32
|
Thx Will do it as soon as I have some time left... > -----Original Message----- > From: pro...@li...=20 > [mailto:pro...@li...] On=20 > Behalf Of Christian Nedreg=E5rd > Sent: samedi 13 mars 2004 15:37 > To: 'Proxool Developer List' > Subject: Re: [Proxool-developer] CodeReview -=20 > AbstractListenerContainer >=20 >=20 >=20 > Good :) >=20 > Thats my piece of verbose code. Have Bill given you commit=20 > rights yet?=20 > If so feel free to replace it with what you suggest. >=20 > CHR >=20 |