// Broken - invokes alien method from synchronized block! - Page 265
package org.effectivejava.examples.chapter10.item67;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class ObservableSet<E> extends ForwardingSet<E> {
public ObservableSet(Set<E> set) {
super(set);
}
private final List<SetObserver<E>> observers = new ArrayList<SetObserver<E>>();
public void addObserver(SetObserver<E> observer) {
synchronized (observers) {
observers.add(observer);
}
}
public boolean removeObserver(SetObserver<E> observer) {
synchronized (observers) {
return observers.remove(observer);
}
}
// This method is the culprit
private void notifyElementAdded(E element) {
synchronized (observers) {
for (SetObserver<E> observer : observers)
observer.added(this, element);
}
}
// Alien method moved outside of synchronized block - open calls - Page 268
// private void notifyElementAdded(E element) {
// List<SetObserver<E>> snapshot = null;
// synchronized(observers) {
// snapshot = new ArrayList<SetObserver<E>>(observers);
// }
// for (SetObserver<E> observer : snapshot)
// observer.added(this, element);
// }
// Thread-safe observable set with CopyOnWriteArrayList - Page 269
//
// private final List<SetObserver<E>> observers =
// new CopyOnWriteArrayList<SetObserver<E>>();
//
// public void addObserver(SetObserver<E> observer) {
// observers.add(observer);
// }
// public boolean removeObserver(SetObserver<E> observer) {
// return observers.remove(observer);
// }
// private void notifyElementAdded(E element) {
// for (SetObserver<E> observer : observers)
// observer.added(this, element);
// }
@Override
public boolean add(E element) {
boolean added = super.add(element);
if (added)
notifyElementAdded(element);
return added;
}
@Override
public boolean addAll(Collection<? extends E> c) {
boolean result = false;
for (E element : c)
result |= add(element); // calls notifyElementAdded
return result;
}
}