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

Java線程間協(xié)作wait、notify和notifyAll詳解

 更新時(shí)間:2023年10月26日 10:00:12   作者:chengmaoning  
這篇文章主要介紹了Java線程間協(xié)作wait、notify和notifyAll詳解,在 Java 中可以用 wait、notify 和 notifyAll 來(lái)實(shí)現(xiàn)線程間的通信,盡管關(guān)于wait和notify的概念很基礎(chǔ),它們也都是Object類的函數(shù),但用它們來(lái)寫代碼卻并不簡(jiǎn)單,,需要的朋友可以參考下

概要描述

在 Java 中可以用 wait、notify 和 notifyAll 來(lái)實(shí)現(xiàn)線程間的通信。盡管關(guān)于wait和notify的概念很基礎(chǔ),它們也都是Object類的函數(shù),但用它們來(lái)寫代碼卻并不簡(jiǎn)單。

wait, notify, notifyAll 都是基類Object的方法,而不屬于Thread,這讓習(xí)慣了調(diào)用Thread.sleep()使線程阻塞的同學(xué)感到奇怪。不過(guò)這樣設(shè)計(jì)是有道理的,因?yàn)檫@些方法操作的鎖(monitor)也是對(duì)象的一部分??梢姡csleep不同,通過(guò)調(diào)用共享對(duì)象的wait方法使當(dāng)前線程等待;通過(guò)調(diào)用對(duì)象的notify, notifyAll 方法喚醒該對(duì)象上的等待線程。

先來(lái)看官方文檔,Java doc對(duì)wait方法的描述:

public final void wait() throws InterruptedException

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

     synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     }

This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

Throws:
    IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.
    InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown. 

Java doc對(duì)notify的描述:

public final void notify()

Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

    By executing a synchronized instance method of that object.
    By executing the body of a synchronized statement that synchronizes on the object.
    For objects of type Class, by executing a synchronized static method of that class. 

Only one thread at a time can own an object's monitor.

Throws:
    IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.

生產(chǎn)者-消費(fèi)者示例:

/**
 * 
 */
public class Producer extends Thread {

    private volatile Queue<Integer> queue;
    private int maxSize;

    public Producer(Queue<Integer> queue, int maxSize) {
        this.queue = queue;
        this.maxSize = maxSize;
    }

    @Override
    public void run() {
        while (true) {
            //wait,notify方法必須在同步代碼中運(yùn)行
            synchronized (queue) {
                //條件一定在循環(huán)中判斷,以防死鎖
                while (queue.size() == maxSize) {
                    try {                             System.out.println(Thread.currentThread().getName() + " wait.");
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                int i = new Random().nextInt();
                System.out.println(Thread.currentThread().getName() + " produce: " + i);
                queue.add(i);
                queue.notifyAll();
            }
        }
    }
}

消費(fèi)者:

 /**
 * 
 */
public class Consumer extends Thread {

    private volatile Queue<Integer> queue;
    private int maxSize;

    public Consumer(Queue<Integer> queue, int maxSize) {
        this.queue = queue;
        this.maxSize = maxSize;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (queue) {
                while (queue.isEmpty()) {
                    try {
                        System.out.println(Thread.currentThread().getName() + " wait.");
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println(Thread.currentThread().getName() + " consume: " + queue.remove());
                queue.notifyAll();
            }
        }
    }
}

main方法:

/**
 * 
 */
public class WaitNotifyMain {

    private volatile static Queue<Integer> queue = new LinkedList<>();

    /**
     * @param args
     */
    public static void main(String[] args) {

        Producer producer = new Producer(queue, 10);
        producer.setName("Producer");//設(shè)置線程名稱
        Consumer consumer = new Consumer(queue, 10);
        consumer.setName("Consumer");

        producer.start();
        consumer.start();

    }

}

打印輸出:

Producer produce: -2017386252
Producer produce: 1186339917
Producer produce: -674757828
Producer produce: 605757848
Producer produce: -539314860
Producer produce: 490590935
Producer produce: -845855520
Producer produce: -1459720588
Producer produce: 1274488529
Producer produce: 55225134
Producer wait.
Consumer consume: -2017386252
Consumer consume: 1186339917
Consumer consume: -674757828
Consumer consume: 605757848
Consumer consume: -539314860
Consumer consume: 490590935
Consumer consume: -845855520
Consumer consume: -1459720588
Consumer consume: 1274488529
Consumer consume: 55225134
Consumer wait.
Producer produce: 673397316
Producer produce: -1176693368
Producer produce: -1707265532
Producer produce: -1614197913
Producer produce: 306171031
Producer produce: -1646438955
Producer produce: 1141572321
Producer produce: 1235215288
Producer produce: -692805724
Producer produce: -2131184778
Producer wait.
Consumer consume: 673397316
Consumer consume: -1176693368

總結(jié)

wait, notify, notifyAll 是共享對(duì)象上的調(diào)用,而不是線程對(duì)象的調(diào)用。

wait, notify, notifyAll一定要在共享對(duì)象同步方法或同步代碼塊中執(zhí)行,否則會(huì)在運(yùn)行時(shí)拋出IllegalMonitorStateException的異常。因?yàn)閣ait, notify, notifyAll包含了對(duì)共享對(duì)象鎖的操作,所以之前一定要先synchronized獲取對(duì)象鎖。

在共享對(duì)象上調(diào)用wait()時(shí),當(dāng)前線程進(jìn)入等待狀態(tài), 并釋放剛獲取的對(duì)象鎖(Thread.sleep()是不釋放鎖的),讓出CPU, 此時(shí),其他線程可以調(diào)用共享對(duì)象的同步方法或代碼塊。

喚醒線程在共享對(duì)象上執(zhí)行notify會(huì)隨機(jī)喚醒該對(duì)象的其中之一等待線程;喚醒線程在共享對(duì)象上執(zhí)行notifyAll會(huì)喚醒該對(duì)象上的所有等待線程;這里要著重注意兩點(diǎn)

A,喚醒線程執(zhí)行完共享對(duì)象的notify或notifyAll方法后,仍然要執(zhí)行完synchronized修飾的同步代碼塊中后面的代碼才能釋放對(duì)象鎖,因此,通常notify后面盡量減少執(zhí)行代碼,讓對(duì)象鎖盡快釋放。

B, 喚醒是指線程ready的狀態(tài),尚未運(yùn)行,共享對(duì)象的鎖被喚醒線程釋放后,ready狀態(tài)的線程跟普通線程一樣需要競(jìng)爭(zhēng)共享對(duì)象的鎖,執(zhí)行同步代碼塊中wait()后面的代碼。

永遠(yuǎn)在循環(huán)(loop)里調(diào)用 wait 和 notify, notifyAll,不是在 If 語(yǔ)句,避免死鎖情況發(fā)生。

基于以上認(rèn)知,下面這個(gè)是使用wait和notify函數(shù)的規(guī)范代碼模板:

// The standard idiom for calling the wait method in Java 
synchronized (sharedObject) { 
    while (condition) { 
    sharedObject.wait(); 
        // (Releases lock, and reacquires on wakeup) 
    } 
    // do action based upon condition e.g. take or put into queue 
}

在while循環(huán)里使用wait的目的,是在線程被喚醒的前后都持續(xù)檢查條件是否被滿足。如果條件并未改變,wait被調(diào)用之前notify的喚醒通知就來(lái)了,那么這個(gè)線程并不能保證被喚醒,有可能會(huì)導(dǎo)致死鎖問(wèn)題。

到此這篇關(guān)于Java線程間協(xié)作wait、notify和notifyAll詳解的文章就介紹到這了,更多相關(guān)Java線程間協(xié)作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA實(shí)現(xiàn)Base64編碼的三種方式

    JAVA實(shí)現(xiàn)Base64編碼的三種方式

    本文主要介紹了JAVA實(shí)現(xiàn)Base64編碼的三種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • SpringBoot整合Camunda工作流實(shí)踐

    SpringBoot整合Camunda工作流實(shí)踐

    工作流是任務(wù)序列的組織方式,BPMN是業(yè)務(wù)流程建模標(biāo)準(zhǔn),Activiti、Flowable、Camunda均源自JBPM,通過(guò)分叉發(fā)展形成不同技術(shù)路線,支持多種數(shù)據(jù)庫(kù),且可與SpringBoot集成部署流程
    2025-09-09
  • 一文詳解Spring事務(wù)的實(shí)現(xiàn)與本質(zhì)

    一文詳解Spring事務(wù)的實(shí)現(xiàn)與本質(zhì)

    這篇文章主要介紹了Spring中事務(wù)的兩種實(shí)現(xiàn)方式:聲明式事務(wù)、編程式事務(wù)以及他們的本質(zhì)。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-04-04
  • JAVA線程用法詳解

    JAVA線程用法詳解

    這篇文章主要介紹了JAVA線程用法,配合實(shí)例針對(duì)Java中線程的開啟、sleep、合并與讓出等進(jìn)行了較為深入的分析,需要的朋友可以參考下
    2014-08-08
  • 解決spring項(xiàng)目找不到Aspect依賴注解的問(wèn)題

    解決spring項(xiàng)目找不到Aspect依賴注解的問(wèn)題

    這篇文章主要介紹了解決spring項(xiàng)目找不到Aspect依賴注解的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java面向?qū)ο筮x擇題總結(jié)歸納

    Java面向?qū)ο筮x擇題總結(jié)歸納

    今天小編就為大家分享一篇關(guān)于Java面向?qū)ο筮x擇題總結(jié)歸納,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Reactive Programming入門概念詳解

    Reactive Programming入門概念詳解

    這篇文章主要為大家介紹了Reactive Programming入門概念詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • springboot系統(tǒng)首頁(yè)自動(dòng)跳轉(zhuǎn)拼接到index的實(shí)現(xiàn)

    springboot系統(tǒng)首頁(yè)自動(dòng)跳轉(zhuǎn)拼接到index的實(shí)現(xiàn)

    文章介紹了通過(guò)訪問(wèn)http://localhost:8091時(shí),服務(wù)器會(huì)動(dòng)態(tài)跳轉(zhuǎn)到系統(tǒng)的歡迎頁(yè)面,實(shí)現(xiàn)原理是在程序啟動(dòng)時(shí)自動(dòng)加載默認(rèn)的請(qǐng)求路徑,并動(dòng)態(tài)拼接前綴和后綴,最終指向./WEB-INF/views/index.jsp,作者分享了這一經(jīng)驗(yàn),并希望得到大家的支持
    2025-11-11
  • 使用springboot防止反編譯proguard+xjar

    使用springboot防止反編譯proguard+xjar

    介紹了三種代碼混淆和加密工具的使用方法:ProGuard、Xjar和ClassFinal,ProGuard用于混淆Java字節(jié)碼,Xjar提供對(duì)JAR包內(nèi)資源的加密和動(dòng)態(tài)解密,而ClassFinal則支持直接加密JAR包或WAR包,通過(guò)預(yù)研和實(shí)際操作
    2024-11-11
  • Springboot集成任務(wù)調(diào)度實(shí)現(xiàn)過(guò)程

    Springboot集成任務(wù)調(diào)度實(shí)現(xiàn)過(guò)程

    這篇文章主要介紹了Springboot集成任務(wù)調(diào)度實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04

最新評(píng)論

乌拉特中旗| 金门县| 雷山县| 香格里拉县| 霍城县| 曲松县| 黑龙江省| 北碚区| 通山县| 乡城县| 清苑县| 湾仔区| 新民市| 芦溪县| 海安县| 句容市| 赞皇县| 轮台县| 岚皋县| 眉山市| 龙海市| 手游| 广河县| 江华| 轮台县| 安远县| 怀来县| 襄樊市| 辽阳市| 德庆县| 百色市| 怀宁县| 建水县| 进贤县| 塔城市| 克什克腾旗| 台前县| 当雄县| 马边| 五寨县| 青阳县|