亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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)寫(xiě)代碼卻并不簡(jiǎn)單,,需要的朋友可以參考下

概要描述

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

wait, notify, notifyAll 都是基類Object的方法,而不屬于Thread,這讓習(xí)慣了調(diào)用Thread.sleep()使線程阻塞的同學(xué)感到奇怪。不過(guò)這樣設(shè)計(jì)是有道理的,因?yàn)檫@些方法操作的鎖(monitor)也是對(duì)象的一部分。可見(jiàn),與sleep不同,通過(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)文章

  • 解決springboot中自定義JavaBean返回的json對(duì)象屬性名稱大寫(xiě)變小寫(xiě)問(wèn)題

    解決springboot中自定義JavaBean返回的json對(duì)象屬性名稱大寫(xiě)變小寫(xiě)問(wèn)題

    開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)查詢返回的數(shù)據(jù)出現(xiàn)自定義的JavaBean的屬性值大小寫(xiě)格式出現(xiàn)問(wèn)題,導(dǎo)致前端無(wú)法接受到數(shù)據(jù),目前有四種解決方法,根據(jù)大佬的經(jīng)驗(yàn)之談,前兩種是最簡(jiǎn)單便捷的,后兩種是比較通用的方法,需要的朋友可以參考下
    2023-10-10
  • 基于JVM性能監(jiān)控命令介紹

    基于JVM性能監(jiān)控命令介紹

    下面小編就為大家?guī)?lái)一篇基于JVM性能監(jiān)控命令介紹。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器

    java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • spring boot整合RabbitMQ(Direct模式)

    spring boot整合RabbitMQ(Direct模式)

    springboot集成RabbitMQ非常簡(jiǎn)單,如果只是簡(jiǎn)單的使用配置非常少,springboot提供了spring-boot-starter-amqp項(xiàng)目對(duì)消息各種支持。下面通過(guò)本文給大家介紹下spring boot整合RabbitMQ(Direct模式),需要的朋友可以參考下
    2017-04-04
  • 使用Apache Ignite實(shí)現(xiàn)Java數(shù)據(jù)網(wǎng)格

    使用Apache Ignite實(shí)現(xiàn)Java數(shù)據(jù)網(wǎng)格

    今天我們來(lái)探討如何使用Apache Ignite來(lái)實(shí)現(xiàn)Java數(shù)據(jù)網(wǎng)格,Apache Ignite是一個(gè)高性能的內(nèi)存計(jì)算平臺(tái),它提供了分布式緩存、數(shù)據(jù)網(wǎng)格和計(jì)算功能,可以顯著提高大規(guī)模應(yīng)用的數(shù)據(jù)處理性能,感興趣的小伙伴跟著小編一起來(lái)看看吧
    2024-08-08
  • Spring Boot與Docker部署實(shí)踐

    Spring Boot與Docker部署實(shí)踐

    這篇文章主要介紹了Spring Boot與Docker部署實(shí)踐,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • SpringBoot整合Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼加減乘除功能

    SpringBoot整合Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼加減乘除功能

    在開(kāi)發(fā)Web應(yīng)用時(shí),驗(yàn)證碼是一個(gè)常見(jiàn)的功能,它可以幫助我們防止機(jī)器人的惡意操作,今天我們將學(xué)習(xí)如何使用Kaptcha生成圖片驗(yàn)證碼,并自定義驗(yàn)證碼內(nèi)容為100以內(nèi)的加減乘除運(yùn)算,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • Java 無(wú)參數(shù)構(gòu)造函數(shù)的應(yīng)用

    Java 無(wú)參數(shù)構(gòu)造函數(shù)的應(yīng)用

    本篇文章主要介紹了Java 無(wú)參數(shù)構(gòu)造函數(shù)的應(yīng)用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • win10和win7下java開(kāi)發(fā)環(huán)境配置教程

    win10和win7下java開(kāi)發(fā)環(huán)境配置教程

    這篇文章主要為大家詳細(xì)介紹了win7下Java開(kāi)發(fā)環(huán)境配置教程,win10下Java開(kāi)發(fā)環(huán)境配置,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Java?詳解如何從尾到頭打印鏈表

    Java?詳解如何從尾到頭打印鏈表

    在我們平時(shí)的代碼過(guò)程中,鏈表是我們經(jīng)常遇到的一個(gè)數(shù)據(jù)結(jié)構(gòu),它非常的簡(jiǎn)單,但Java并不能直接將一個(gè)鏈表打印出來(lái),通過(guò)這篇文章我們來(lái)講解一下這個(gè)問(wèn)題
    2022-01-01

最新評(píng)論