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的時候,共享的值已經改變了。
相關文章
相關標籤/搜索