1+ package bestpractice ;
2+
3+ import java .util .*;
4+ import java .util .concurrent .CopyOnWriteArrayList ;
5+ import java .util .concurrent .ExecutionException ;
6+ import java .util .concurrent .ExecutorService ;
7+ import java .util .concurrent .Executors ;
8+
9+ //don't run alien methods on sync blocks, it can cause exceptions, deadlocks, or data corruption
10+ //you should do as little work as possible inside synchronized regions
11+ public class AvoidExcessiveSync {
12+ public static void main (String [] args ) {
13+ ObservableSet <Integer > set = new ObservableSet <Integer >(new HashSet <Integer >());
14+ set .addObserver (new SetObserver <Integer >() {
15+ public void added (ObservableSet <Integer > s , Integer e ) {
16+ System .out .println (e );
17+ if (e == 20 ) {
18+ ExecutorService executor = Executors .newSingleThreadExecutor ();
19+ final SetObserver <Integer > observer = this ;
20+ try {
21+ executor .submit (new Runnable () {
22+ public void run () {
23+ s .removeObserver (observer );
24+ }
25+ }).get ();
26+ } catch (ExecutionException | InterruptedException ex ) {
27+ throw new AssertionError (ex .getCause ());
28+ } finally {
29+ executor .shutdown ();
30+ }
31+ }
32+ }
33+ });
34+ for (int i = 0 ; i < 100 ; i ++)
35+ set .add (i );
36+ }
37+ }
38+ class ObservableSet <E > extends HashSet <E > {
39+ public ObservableSet (Set <E > set ) { super (set ); }
40+ private final List <SetObserver <E >> observers = new CopyOnWriteArrayList <>();
41+ public synchronized void addObserver (SetObserver <E > observer ) {
42+ observers .add (observer );
43+ }
44+ public synchronized boolean removeObserver (SetObserver <E > observer ) {
45+ return observers .remove (observer );
46+ }
47+ private void notifyElementAdded (E element ) {
48+ for (SetObserver <E > observer : observers )
49+ observer .added (this , element );
50+ }
51+ @ Override public boolean add (E element ) {
52+ boolean added = super .add (element );
53+ if (added )
54+ notifyElementAdded (element );
55+ return added ;
56+ }
57+ @ Override public boolean addAll (Collection <? extends E > c ) {
58+ boolean result = false ;
59+ for (E element : c )
60+ result |= add (element );
61+ return result ;
62+ }
63+ }
64+ interface SetObserver <E > {
65+ void added (ObservableSet <E > set , E element );
66+ }
67+
68+ // if (e == 20) s.removeObserver(this);
69+ // if (e == 20) {
70+ // ExecutorService executor = Executors.newSingleThreadExecutor();
71+ // final SetObserver<Integer> observer = this;
72+ // try {
73+ // executor.submit(new Runnable() {
74+ // public void run() {
75+ // s.removeObserver(observer);
76+ // }
77+ // }).get();
78+ // } catch (ExecutionException | InterruptedException ex) {
79+ // throw new AssertionError(ex.getCause());
80+ // } finally {
81+ // executor.shutdown();
82+ // }
83+ // }
84+
85+ // List<SetObserver<E>> snapshot = null;
86+ //synchronized(observers) {
87+ // snapshot = new ArrayList<>(observers);
88+ // }
89+ // for (SetObserver<E> observer : snapshot)
90+ // observer.added(this, element);
0 commit comments