最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java的wait(), notify()和notifyAll()使用心得

 更新時間:2013年08月21日 14:46:00   作者:  
本篇文章是對java的 wait(),notify(),notifyAll()進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
wait(),notify()和notifyAll()都是java.lang.Object的方法:
wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
notify(): Wakes up a single thread that is waiting on this object's monitor.
notifyAll(): Wakes up all threads that are waiting on this object's monitor.
這三個方法,都是Java語言提供的實現(xiàn)線程間阻塞(Blocking)和控制進(jìn)程內(nèi)調(diào)度(inter-process communication)的底層機(jī)制。在解釋如何使用前,先說明一下兩點:
1. 正如Java內(nèi)任何對象都能成為鎖(Lock)一樣,任何對象也都能成為條件隊列(Condition queue)。而這個對象里的wait(), notify()和notifyAll()則是這個條件隊列的固有(intrinsic)的方法。
2. 一個對象的固有鎖和它的固有條件隊列是相關(guān)的,為了調(diào)用對象X內(nèi)條件隊列的方法,你必須獲得對象X的鎖。這是因為等待狀態(tài)條件的機(jī)制和保證狀態(tài)連續(xù)性的機(jī)制是緊密的結(jié)合在一起的。
(An object's intrinsic lock and its intrinsic condition queue are related: in order to call any of the condition queue methods on object X, you must hold the lock on X. This is because the mechanism for waiting for state-based conditions is necessarily tightly bound to the mechanism fo preserving state consistency)
根據(jù)上述兩點,在調(diào)用wait(), notify()或notifyAll()的時候,必須先獲得鎖,且狀態(tài)變量須由該鎖保護(hù),而固有鎖對象與固有條件隊列對象又是同一個對象。也就是說,要在某個對象上執(zhí)行wait,notify,先必須鎖定該對象,而對應(yīng)的狀態(tài)變量也是由該對象鎖保護(hù)的。
知道怎么使用后,我們來問下面的問題:
1. 執(zhí)行wait, notify時,不獲得鎖會如何?
請看代碼:
復(fù)制代碼 代碼如下:

public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        obj.wait();
        obj.notifyAll();
}

執(zhí)行以上代碼,會拋出java.lang.IllegalMonitorStateException的異常。
2. 執(zhí)行wait, notify時,不獲得該對象的鎖會如何?
請看代碼:
復(fù)制代碼 代碼如下:

public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Object lock = new Object();
        synchronized (lock) {
            obj.wait();
            obj.notifyAll();
        }
    }

執(zhí)行代碼,同樣會拋出java.lang.IllegalMonitorStateException的異常。
3. 為什么在執(zhí)行wait, notify時,必須獲得該對象的鎖?
這是因為,如果沒有鎖,wait和notify有可能會產(chǎn)生競態(tài)條件(Race Condition)。考慮以下生產(chǎn)者和消費者的情景:
1.1生產(chǎn)者檢查條件(如緩存滿了)-> 1.2生產(chǎn)者必須等待
2.1消費者消費了一個單位的緩存 -> 2.2重新設(shè)置了條件(如緩存沒滿) -> 2.3調(diào)用notifyAll()喚醒生產(chǎn)者
我們希望的順序是: 1.1->1.2->2.1->2.2->2.3
但在多線程情況下,順序有可能是 1.1->2.1->2.2->2.3->1.2。也就是說,在生產(chǎn)者還沒wait之前,消費者就已經(jīng)notifyAll了,這樣的話,生產(chǎn)者會一直等下去。
所以,要解決這個問題,必須在wait和notifyAll的時候,獲得該對象的鎖,以保證同步。
請看以下利用wait,notify實現(xiàn)的一個生產(chǎn)者、一個消費者和一個單位的緩存的簡單模型:
復(fù)制代碼 代碼如下:

public class QueueBuffer {
    int n;
    boolean valueSet = false;
    synchronized int get() {
        if (!valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }
    synchronized void put(int n) {
        if (valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

復(fù)制代碼 代碼如下:

public class Producer implements Runnable {
    private QueueBuffer q;
    Producer(QueueBuffer q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while (true) {
            q.put(i++);
        }
    }
}

復(fù)制代碼 代碼如下:

public class Consumer implements Runnable {
    private QueueBuffer q;
    Consumer(QueueBuffer q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while (true) {
            q.get();
        }
    }
}

復(fù)制代碼 代碼如下:

public class Main {
    public static void main(String[] args) {
        QueueBuffer q = new QueueBuffer();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}

所以,JVM通過在執(zhí)行的時候拋出IllegalMonitorStateException的異常,來確保wait, notify時,獲得了對象的鎖,從而消除隱藏的Race Condition。
最后來看看一道題:寫一個多線程程序,交替輸出1,2,1,2,1,2......
利用wait, notify解決:
復(fù)制代碼 代碼如下:

public class OutputThread implements Runnable {
    private int num;
    private Object lock;
    public OutputThread(int num, Object lock) {
        super();
        this.num = num;
        this.lock = lock;
    }
    public void run() {
        try {
            while(true){
                synchronized(lock){
                    lock.notifyAll();
                    lock.wait();
                    System.out.println(num);
                }
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        final Object lock = new Object();
        Thread thread1 = new Thread(new OutputThread(1,lock));
        Thread thread2 = new Thread(new OutputThread(2, lock));
        thread1.start();
        thread2.start();
    }
}

相關(guān)文章

  • Java?C++題解leetcode902最大為N的數(shù)字組合數(shù)位DP

    Java?C++題解leetcode902最大為N的數(shù)字組合數(shù)位DP

    這篇文章主要為大家介紹了Java?C++題解leetcode902最大為N的數(shù)字組合數(shù)位DP,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 淺談Spring事務(wù)傳播行為實戰(zhàn)

    淺談Spring事務(wù)傳播行為實戰(zhàn)

    這篇文章主要介紹了淺談Spring事務(wù)傳播行為實戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java類型轉(zhuǎn)換valueOf與parseInt區(qū)別探討解析

    Java類型轉(zhuǎn)換valueOf與parseInt區(qū)別探討解析

    這篇文章主要為大家介紹了Java類型轉(zhuǎn)換valueOf與parseInt區(qū)別探討解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解Java線程同步器CountDownLatch

    詳解Java線程同步器CountDownLatch

    這篇文章主要介紹了Java線程同步器CountDownLatch的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-09-09
  • MyBatis查詢緩存實例詳解

    MyBatis查詢緩存實例詳解

    查詢緩存的使用,主要是為了提高查詢訪問速度。這篇文章主要介紹了MyBatis查詢緩存,需要的朋友可以參考下
    2017-06-06
  • 基于CXF搭建webService的實例講解

    基于CXF搭建webService的實例講解

    下面小編就為大家?guī)硪黄贑XF搭建webService的實例講解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • Java 讀取文件方法大全

    Java 讀取文件方法大全

    這篇文章主要介紹了Java 讀取文件方法大全,需要的朋友可以參考下
    2014-11-11
  • 基于Spring整合mybatis注解掃描是否成功的問題

    基于Spring整合mybatis注解掃描是否成功的問題

    這篇文章主要介紹了Spring整合mybatis注解掃描是否成功的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • mybatis-plus讀取JSON類型的方法實現(xiàn)

    mybatis-plus讀取JSON類型的方法實現(xiàn)

    這篇文章主要介紹了mybatis-plus讀取JSON類型的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringBoot項目整合Redis教程詳解

    SpringBoot項目整合Redis教程詳解

    這篇文章主要介紹了SpringBoot項目整合Redis教程詳解,Redis?是完全開源的,遵守?BSD?協(xié)議,是一個高性能的?key-value?數(shù)據(jù)庫。感興趣的小伙伴可以參考閱讀本文
    2023-03-03

最新評論

秦安县| 永靖县| 宝坻区| 青铜峡市| 天门市| 遵义市| 民和| 二连浩特市| 铁岭县| 永济市| 昭苏县| 遵化市| 天镇县| 洪泽县| 隆林| 北川| 水富县| 深泽县| 康马县| 仙游县| 万全县| 始兴县| 涿鹿县| 惠东县| 邮箱| 星子县| 拜城县| 休宁县| 区。| 湘阴县| 贵南县| 广汉市| 高尔夫| 张北县| 苍山县| 沅江市| 兰坪| 历史| 梅河口市| 绥阳县| 香格里拉县|