This class avoids code duplication in as many place as possible. Its goal is to provide a listener lists using reference counted pointers, so that multiple listener registration still results in only one notification, and there is no memory leaks. See the long comment below. Warning : use external synchronization on the manager before using the size() and get(int) methods, as otherwise the size may vary according to the whims of the garbage collector. The synchronized block should englobe both the size() and get(int) calls.
@author nicolas brodu
Tricky Java... When an object registered as listener becomes unused, the fact that the listener list holds a reference to it prevents it from beeing fred by the garbage collector. This ends up in objects not being fred, and growing listener lists of unused objects. This is bad, and listener lists are a very common source of memory leak! Beware! A naive and developper-unfriendly approach would be to tell all registering objects to unregister before they are unsued... This is easy to do in C++ where there are proper destructors, but in Java the finalize() method is precisely called by the garbage collector, which won't call it in the present case since the listener list still holds a reference. Back to the beginning. An even-more developer unfriendly approach would impose a constraint on all objects using objects registered as listeners to do the cleanup, but this is a real mess and does not even work for other reasons (for example, think of inner classes registering private members as listeners, or other awful cases where the object using another object using another object using... has no way of unregistering a listerner without modifying drastically the API just for that). Weak references were introduced in Java 1.2 to solve this problem. If only weak references to an object remains, the garbage collector discards it. The get() method of the weak reference holder then returns null. A queue can be used to be notified when this happens, as the application does not decides when the object is finalized (this is handled by the garbage collector thread). Thus, weak reference pointers may become invalid any time! For JSynoptic, we have an additional problem. The same object may be registered as listener several times, but should be notified only once. See EndNotificationListener for a concrete example of this. Also, a Set is not adapted to hold only one reference of each listener. If an object is registered twice by two different paths and unregistered only once, it is still expected to be notified by the second registering path. Hence, it must still be present in the listener list, which would not be the case using a Set. The solution is of course reference counting, which is applied on the register/unregister operation. This is complementary to the WeakReference mecanism : if an object forgets to unregister or doesn't have the occasion to do it before being thrown away, then the weak reference mecanism will still discard it even if the refcount field is >1, which is what we want. On the other hand, if the refcount field goes down to 0, the object is removed from the listener list, but this does not necessarily mean the listener is unused. It may just have unregistered and live its life as usual. As in this case the listener list does not hold any reference to the object, it cannot be the source for a memory leak. So, the refcount field is NOT related to the weak reference mecanism. It is necessary for another reason entirely, as decribed above. See the notes below for more fun with the ReferenceCountedPointer class. It holds a weak reference to the ListenerManager, so as to avoid the same problem as above, but for the managers themselves.