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编辑  收藏  举报

导航