jdk1.8观察者、被观察者类源码解读,通知方法是线程不安全方法,慎用!
看源码通知观察者的方法
1 public void notifyObservers(Object arg) { 2 /* 3 * a temporary array buffer, used as a snapshot of the state of 4 * current Observers. 5 */ 6 Object[] arrLocal; 7 8 synchronized (this) { 9 /* We don't want the Observer doing callbacks into 10 * arbitrary code while holding its own Monitor. 11 * The code where we extract each Observable from 12 * the Vector and store the state of the Observer 13 * needs synchronization, but notifying observers 14 * does not (should not). The worst result of any 15 * potential race-condition here is that: 16 * 1) a newly-added Observer will miss a 17 * notification in progress 18 * 2) a recently unregistered Observer will be 19 * wrongly notified when it doesn't care 20 */ 21 if (!changed) 22 return; 23 arrLocal = obs.toArray(); 24 clearChanged(); 25 } 26 27 for (int i = arrLocal.length-1; i>=0; i--) 28 ((Observer)arrLocal[i]).update(this, arg); 29 }
上面是,通知已注册的观察者方法,这里只有中间一部分用了 synchronized来保证局部阻塞,注意,这里使用了一个参数changed来判断是否需要通知观察者,这里去看看更新changed的方法。
1 /** 2 * Marks this <tt>Observable</tt> object as having been changed; the 3 * <tt>hasChanged</tt> method will now return <tt>true</tt>. 4 */ 5 protected synchronized void setChanged() { 6 changed = true; 7 }
在每次想要通知后续观察者时候,需要调用setChanged方法,来改变changed参数值为true,才能通知到后续观察者。
再看第一段源码的clearChanged方法
/** * Indicates that this object has no longer changed, or that it has * already notified all of its observers of its most recent change, * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>. * This method is called automatically by the * <code>notifyObservers</code> methods. * * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) */ protected synchronized void clearChanged() { changed = false; }
这个正好和setChanged相反。
从这两个方法中可以看出观察者方法的设计思路和用法,观察者观察被观察者时候,当被观察者有动作,就能被观察到,在代码中呢,这个动作就相当于changed参数,当动作发生,变改changed=true,通知观察者,当捕获到这次动作,遍设置changed=false。
当如果这个被观察者在多线程状态下短时间内多次触发了changed=true并且通知观察者操作,那么可能在执行notifyObservers方法的时候,另一个线程执行了clearChanged方法,然后在判断changed时候与预期不符合。
这就是被观察者多线程下的用法错误。
posted on 2019-10-03 11:23 SaltFishYe 阅读(257) 评论(2) 编辑 收藏 举报