Java Observer/Observable caveat
April 23rd, 2010
This post is also available in: French
ProActive Virtual Machine Management is a project in which I am invested. In several places we needed to use the Java Observer/Observable pattern but weren’t really satisfied by the way Observers are saved, this way can leads to important memory leaks in APIs where the end user doesn’t not explicitly release objects. Indeed, all listeners are not garbagge collected just because they are in the listener list.
To avoid memory leaks, we wrote our own Observer/Obserable feature based on WeakReference. Here is the code:
NotifierAdapter class is the equivalent of Observable
public class NotifierAdapter implements Notifier { private ArrayList<WeakReference<NotifierListener<N, T>>> listeners = new ArrayList<WeakReference<NotifierListener<N, T>>>(); private N notifier; protected NotifierAdapter() { this.notifier = (N) this; } public NotifierAdapter(N notifier) { this.notifier = notifier; } public void addNotifierListener(NotifierListener<N, T> listener) { WeakReference<NotifierListener<N, T>> weakListenerReference = new WeakReference<NotifierListener<N, T>>(listener); this.listeners.add(weakListenerReference); } public void removeNotifierListener(NotifierListener<N, T> listener) { for (int i = 0; i < this.listeners.size(); i++) { WeakReference<NotifierListener<N, T>> weakListenerReference = this.listeners.get(i); NotifierListener<N, T> weakListener = weakListenerReference.get(); if ((weakListener == null) || (weakListener == listener)) { this.listeners.remove(weakListenerReference); } } } public void fire(T event) { ArrayList<WeakReference<NotifierListener<N, T>>> toDelete = new ArrayList<WeakReference<NotifierListener<N, T>>>(); for (WeakReference<NotifierListener<N, T>> weakListenerReference : listeners) { NotifierListener<N, T> weakListener = weakListenerReference.get(); if (weakListener == null) { toDelete.add(weakListenerReference); } else { weakListener.update(this.notifier, event); } } listeners.removeAll(toDelete); } }
The equivalent of the Observer interface: NotifierListener
public interface NotifierListener { public void update(N notifier, T event); }
And the Notifier interface
public interface Notifier { public void addNotifierListener(NotifierListener listener); public void removeNotifierListener(NotifierListener listener); public void fire(T event); }
English
Français