java 虚假唤醒(SpuriousWakeups)

public class SpuriousWakeups {    private Object object  = new Object();    public int count = 0;    public void get(int cnt) {        synchronized (object) {            if (count <= 0) {                try {                    object.wait();                }                catch (InterruptedException e) {                    e.printStackTrace();                }            }            count = count - cnt;            System.out.println(Thread.currentThread() + ": final " + count);        }    }    public  void put(int cnt) {        synchronized (object) {            count = count + cnt;            object.notify();        }    }    public static void main(String[] args) throws InterruptedException {        SpuriousWakeups spuriousWakeups = new SpuriousWakeups();        Thread put1 = new Thread(new Runnable() {            @Override public void run() {                spuriousWakeups.put(1);            }        });        Thread get1 = new Thread(new Runnable() {            @Override public void run() {                spuriousWakeups.get(1);            }        });        Thread get2 = new Thread(new Runnable() {            @Override public void run() {                spuriousWakeups.get(1);            }        });        //get2.setPriority(9);        // get1先获取, 让object.wait 释放object的monitor        get1.start();        Thread.sleep(100);        // 放入数据        put1.start();        get2.start();    }}执行的结果是:    一、    Thread[Thread-1,5,main]: final 0    get1获取monitor往下执行,结束后释放monitor;get2得到get1释放的monitor,其线程由BLOCKED状态转为WAITING状态    二、    Thread[Thread-2,5,main]: final 0    Thread[Thread-1,5,main]: final -1    get2抢先得到monitor执行完毕后,get1得到get2释放的monitor。至此线程所有执行完毕。 JDK推荐的写法:    public final void wait()    throws InterruptedException致使当前线程等待,直到另外一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。    当前的线程必须拥有该对象的显示器。 该线程释放此监视器的全部权,并等待另外一个线程通知等待该对象监视器的线程经过调用notify方法或notifyAll方法notifyAll 。 而后线程等待,直到它能够从新得到监视器的全部权并恢复执行。    像在一个参数版本中,中断和虚假唤醒是可能的,而且该方法应该始终在循环中使用:    synchronized (obj) {        while (<condition does not hold>)               obj.wait();    ... // Perform action appropriate to condition    } 该方法只能由做为该对象的监视器的全部者的线程调用。 有关线程能够成为监视器全部者的方式的说明,请参阅notify方法。    线程状态。 线程能够处于如下状态:    NEW    还没有启动的线程处于此状态。    RUNNABLE    在Java虚拟机中执行的线程处于此状态。    BLOCKED    被阻塞等待监视器锁定的线程处于此状态。    WAITING    正在等待另外一个线程执行特定动做的线程处于此状态。    TIMED_WAITING    正在等待另外一个线程执行动做达到指定等待时间的线程处于此状态。    TERMINATED    已退出的线程处于此状态。    总结:    虚假唤醒缘由:wait被notify后,线程由WAITING变成BLOCKED状态,来竞争monitor,可是另一个线程BLOCKED也会来竞争monitor,是无法控制究竟是谁先拿到monitor的。    若是不是wait的线程先拿到monitor,那当wait的线程拿到monitor的时候,共享的值已经改变了。
相关文章
相关标签/搜索