java中wait和notify的關系


    java中,wait和notify這兩個方法是一對,wait方法阻塞當前線程,而notify是喚醒被wait方法阻塞的線程。

    首先,需要說明的是,wait和notify方法都是Object的實例方法,要執行這兩個方法,有一個前提就是,當前線程必須獲其對象的monitor(俗稱“鎖”),否則會拋出 IllegalMonitorStateException 異常,所以這兩個方法必須在同步塊代碼里面調用,經典的生產者和消費者模型就是使用這兩個方法實現的。
    當前線程A獲得對象obj的monitor,然后進入臨界區(同步代碼塊),調用對象obj的wait方法,則線程A釋放obj的monitor(執行了obj的wati方法之后,就會釋放obj的monitor,不用等到執行完臨界區,因為線程A會被阻塞在當前這個位置,同時cpu的相關寄存器會記住當前位置的堆棧信息),然后進入阻塞狀態,同時線程A讓出cpu,不再參與cpu的競爭,但是還會同時wait方法內部會不斷地輪詢線程A的InterruptStatus狀態位(其實導致阻塞的方法一般都會做這個操作,就是不斷地輪詢中斷狀態位,以判斷當前被阻塞的線程是否被提前取消了),以判斷當前阻塞的狀態是否會被中斷(這里有點小矛盾,照理線程A不再參與cpu的競爭,又還不斷輪詢中斷狀態位,這個我還要研究下,有知道的可以留言評論指出,謝謝),等待其他線程調用A的notify(或notifyAll)來喚醒;然后線程B獲取的obj的monitor之后,進去臨界區,執行obj的notify方法,這時候,有點和wait方法不一樣,就是調用了obj的notify之后,不會立刻釋放obj的monitor同時喚醒線程A,而是要等到線程B執行完同步塊代碼,出了臨界區,這時候才會釋放obj的monitor,同時喚醒線程A,這時候線程A就會從新參與cpu的競爭,就有機會(因為可能其他線程也在競爭obj的monitor,如果之前有幾個線程都在等待被obj的notify喚醒,則這時候就會有幾個線程同時被喚醒,喚醒之后,因為obj的monitor同一時刻只允許一個線程擁有,所以被喚醒的幾個線程究竟誰先獲得obj的monitor繼續往下面執行呢?這個就是根據操作系統的調度算法了。一個執行完同步塊代碼,釋放obj的monitor之后,其他被喚醒的線程才會一個一個競爭獲取obj的monitor,繼續執行其wait方法后面的代碼...)獲取的obj的monitor,等到線程A重新獲得obj的monitor之后,線程A會進入臨界區,從wait方法后面繼續執行(注意:這里進入臨界區之后,不會從新從頭執行臨界區代碼塊,而會根據之前調用wait方法阻塞的時候,cpu記住的堆棧信息,會直接從wait方法后面的代碼開始繼續往下執行),直到出了臨界區,釋放obj的monitor。
    這里還有一個要注意的問題就是,wait和notify調用的順序一定要注意先后,如果先調用了obj的notify,然后才調用obj的wait方法的話,則調用了wait方法被阻塞的線程則不會被喚醒,會一直處於阻塞狀態。
    以下是我參考(http://www.cnblogs.com/hapjin/p/5492645.html)代碼做的實踐:
    Service類
/**
 * Created by regis on 2017/4/23.
 */
public class Service {
    public void testMethod(Object lock) {
        try {
            synchronized (lock) {
                System.out.println("begin wait() ThreadName=" + Thread.currentThread().getName());
                lock.wait();
                if (Thread.currentThread().getName().equals("Thread-1")) {
                    Thread.sleep(50000);
                }
                System.out.println("end wait() ThreadName=" + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void synNotifyMethod(Object lock) {
        synchronized (lock) {
            System.out.println("begin notify() ThreadName=" + Thread.currentThread().getName());
            lock.notifyAll();
            System.out.println("end notify() ThreadName=" + Thread.currentThread().getName());
        }
    }
}

 

    SynNotifyMethodThread類
/**
 * Created by regis on 2017/4/23.
 */
public class SynNotifyMethodThread extends Thread {
    private Object lock;
    public SynNotifyMethodThread(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        Service service = new Service();
        service.synNotifyMethod(lock);
    }
}

 

    測試類
/**
 * Created by regis on 2017/4/20.
 */
public class Test {
    public static void main(String[] args) {
        Object lock = new Object();
        ThreadA a = new ThreadA(lock);
        a.start();
        ThreadA b = new ThreadA(lock);
        b.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SynNotifyMethodThread c = new SynNotifyMethodThread(lock);
        c.start();
    }
}

 

    ThreadA類
/**
 * Created by regis on 2017/4/23.
 */
public class ThreadA extends Thread{
    private Object lock;
    public ThreadA(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        Service service = new Service();
        service.testMethod(lock);
    }
}

 

參考:http://www.cnblogs.com/hapjin/p/5492645.html
 






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM