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

Java通過notify和wait實(shí)現(xiàn)線程間的通信功能

 更新時(shí)間:2024年06月24日 08:41:22   作者:shengjk1  
在軟件開發(fā)中,線程是實(shí)現(xiàn)并發(fā)執(zhí)行的重要手段,然而,線程之間的協(xié)作與通信卻是開發(fā)者必須重點(diǎn)考慮的挑戰(zhàn)之一,Java作為一種廣泛應(yīng)用于多線程編程的語言,本文將深入探討Java中通過notify和wait實(shí)現(xiàn)線程間通信的機(jī)制,需要的朋友可以參考下

一、前言

在軟件開發(fā)中,線程是實(shí)現(xiàn)并發(fā)執(zhí)行的重要手段,然而,線程之間的協(xié)作與通信卻是開發(fā)者必須重點(diǎn)考慮的挑戰(zhàn)之一。Java作為一種廣泛應(yīng)用于多線程編程的語言,提供了一套強(qiáng)大而靈活的機(jī)制,讓不同線程之間能夠優(yōu)雅地交替執(zhí)行、傳遞信息,以實(shí)現(xiàn)協(xié)調(diào)合作。

本文將深入探討Java中通過notifywait實(shí)現(xiàn)線程間通信的機(jī)制。

二、notify 和 wait

2.1 wait

2.1.1 wait 基本介紹

通過源碼我們可以知道 wait 是 object 對象方法,用于實(shí)現(xiàn)線程間的等待和通知機(jī)制。當(dāng)一個(gè)線程調(diào)用wait()方法時(shí),它會(huì)釋放當(dāng)前所持有的對象鎖,并進(jìn)入等待狀態(tài),直到被其他線程調(diào)用相同對象上的notify()notifyAll()方法喚醒。

public final void wait() throws InterruptedException {
    wait(0);
}

2.1.2 wait 注意點(diǎn)

  • 要想使用wait方法,當(dāng)前線程必須擁有對應(yīng) object 的 mointor,即必須要擁有對應(yīng)對象的鎖,否則會(huì)報(bào)java.lang.IllegalMonitorStateException 比如:
Object o = new Object();
o.wait(); //java.lang.IllegalMonitorStateException
  • 當(dāng)調(diào)用wait()方法的線程被另一個(gè)線程中斷時(shí),wait()方法會(huì)拋出InterruptedException異常。
  • 線程也可能會(huì)在沒有收到通知、中斷或超時(shí)的情況下被喚醒,即所謂的虛假喚醒。雖然這種情況在實(shí)踐中很少發(fā)生,但應(yīng)用程序必須通過測試應(yīng)該導(dǎo)致線程被喚醒的條件來防范這種情況,如果條件不滿足,則繼續(xù)等待。換句話說,等待應(yīng)該總是在循環(huán)中發(fā)生,如下所示:
   synchronized (obj) {
          while (<condition does not hold>)
              obj.wait(timeout);
          ... // Perform action appropriate to condition
      }

2.1.3 wait 使用場景

wait()方法是在Java中用于線程間通信和同步的重要方法之一。它通常與synchronized關(guān)鍵字一起使用,用于在多線程中協(xié)調(diào)線程之間的操作。下面是wait()方法的一些常見使用場景:

  • 協(xié)調(diào)多個(gè)線程的操作wait()方法通常與notify()notifyAll()方法一起使用,用于在多線程之間協(xié)調(diào)操作。一個(gè)線程可以調(diào)用wait()進(jìn)入等待狀態(tài),等待其他線程調(diào)用相同對象的notify()notifyAll()方法來喚醒它。
  • 等待條件滿足:線程可以調(diào)用wait()方法等待某個(gè)條件的滿足。例如,一個(gè)線程可能等待某個(gè)變量的值發(fā)生改變或者等待某個(gè)事件發(fā)生。
  • 線程安全的隊(duì)列實(shí)現(xiàn)wait()方法常用于實(shí)現(xiàn)線程安全的隊(duì)列。當(dāng)隊(duì)列為空時(shí),消費(fèi)者線程調(diào)用wait()等待生產(chǎn)者線程向隊(duì)列中添加元素;當(dāng)隊(duì)列已滿時(shí),生產(chǎn)者線程調(diào)用wait()等待消費(fèi)者線程從隊(duì)列中取走元素。
  • 實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型wait()方法在生產(chǎn)者-消費(fèi)者模型中起著重要作用。生產(chǎn)者向共享的緩沖區(qū)添加數(shù)據(jù)時(shí),如果緩沖區(qū)已滿,生產(chǎn)者線程調(diào)用wait()等待消費(fèi)者取走數(shù)據(jù);消費(fèi)者從緩沖區(qū)取數(shù)據(jù)時(shí),如果緩沖區(qū)為空,消費(fèi)者線程調(diào)用wait()等待生產(chǎn)者添加數(shù)據(jù)。
  • 線程間通信wait()方法是線程間通信的重要手段之一。線程可以通過等待并喚醒的機(jī)制來實(shí)現(xiàn)信息的傳遞和協(xié)調(diào)。

2.1.4 wait 的執(zhí)行原理

  • 當(dāng)線程調(diào)用wait()方法時(shí),它會(huì)釋放當(dāng)前持有的對象鎖,使得其他線程可以訪問這個(gè)對象并執(zhí)行同步代碼塊。
  • 調(diào)用wait()方法的線程會(huì)進(jìn)入對象的等待隊(duì)列,等待其他線程調(diào)用相同對象的notify()notifyAll()方法來喚醒它。
  • 當(dāng)另一個(gè)線程調(diào)用相同對象notify()方法或notifyAll()方法時(shí),等待隊(duì)列中的線程會(huì)被喚醒,然后競爭對象的鎖。
  • 喚醒的線程會(huì)嘗試重新獲取對象鎖,然后繼續(xù)執(zhí)行。

2.1.5 wait 使用

  • wait()或者wait(0): 調(diào)用該方法的線程進(jìn)入WAITING狀態(tài),只有等待另外線程的通知或被中斷才會(huì)返回,需要注意調(diào)用 wait() 方法后,會(huì)釋放對象的鎖
  • wait(long) 會(huì)釋放鎖,超時(shí)等待一段時(shí)間,這里的參數(shù)時(shí)間是毫秒,也就是等待長達(dá)毫秒,如果沒有通知就超時(shí)返回
  • wait(long,int) 會(huì)釋放鎖,該方法與 wait(long) 類似,多了一個(gè) nanos 參數(shù),這個(gè)參數(shù)表示額外時(shí)間(以納秒為單位,范圍是 0-999999), 所以超時(shí)的時(shí)間還需要加上 nanos 納秒。

2.2 notify

首先我們需要知道 nofity 和 notifyall 基本上是等價(jià)的,如沒有特別標(biāo)明,nofity 和 nofityall 是一樣的

2.2.1 notify 基本介紹

通過源碼我們可以知道 notify 是 object 對象方法。

notify()是線程間通信的一種機(jī)制,用于喚醒在當(dāng)前對象上等待的一個(gè)線程。當(dāng)一個(gè)線程調(diào)用notify()方法時(shí),它會(huì)喚醒正在該對象上等待的單個(gè)線程(如果有多個(gè)線程在等待,系統(tǒng)無法確定哪個(gè)線程會(huì)被喚醒,因?yàn)檫x擇是隨機(jī)的)。這個(gè)被喚醒的線程將從等待狀態(tài)變?yōu)榭蛇\(yùn)行狀態(tài),但并不意味著立即獲得對象的鎖。

public final native void notify();

當(dāng)一個(gè)線程調(diào)用notifyAll()時(shí),它會(huì)喚醒在當(dāng)前對象上等待的所有線程,使它們從等待狀態(tài)轉(zhuǎn)變?yōu)榭蛇\(yùn)行狀態(tài)。這樣,所有等待中的線程都有機(jī)會(huì)爭取獲取對象鎖,在某個(gè)線程獲得鎖后,它們會(huì)競爭執(zhí)行。

2.2.2 notify 注意點(diǎn)

下面是關(guān)于notify()方法的一些重要點(diǎn):

  • 使用條件變量notify()方法通常與條件變量一起使用,用于線程間的協(xié)作。一個(gè)線程等待某個(gè)條件變?yōu)檎妫硪粋€(gè)線程在某種情況下會(huì)改變條件,并調(diào)用notify()來通知等待的線程。
  • notifyAll()方法:與notify()不同的是,notifyAll()方法喚醒在當(dāng)前對象上等待的所有線程,而不僅僅是一個(gè)線程。這樣做可以避免遺漏任何等待中的線程,但同一時(shí)間獲取鎖的只會(huì)有一個(gè)線程。
  • Object類中的方法notify()方法是Object類的一個(gè)方法,因此任何Java對象都可以調(diào)用notify()wait()方法來進(jìn)行線程間的通信。
  • 必須在同步塊中調(diào)用:為了調(diào)用notify()方法,必須在同步塊(synchronized塊)中對包含該對象的鎖進(jìn)行操作。
  • 隨機(jī)性:當(dāng)多個(gè)線程在同一個(gè)對象上等待時(shí),調(diào)用notify()會(huì)隨機(jī)選擇一個(gè)線程喚醒,因此不能確定哪個(gè)線程會(huì)被喚醒。
  • 喚醒等待線程:被喚醒的線程會(huì)嘗試重新獲取對象鎖,一旦獲得鎖,它會(huì)從wait()方法返回,并繼續(xù)執(zhí)行后續(xù)代碼。

2.2.3 nofityall

以下是關(guān)于notifyAll()方法的詳細(xì)介紹:

  • 喚醒所有等待線程notifyAll()方法被調(diào)用時(shí),會(huì)喚醒在當(dāng)前對象上等待的所有線程,使它們從阻塞狀態(tài)轉(zhuǎn)變?yōu)榫途w狀態(tài)。這樣,所有等待中的線程都有機(jī)會(huì)去競爭獲取對象的鎖。
  • 解決等待問題notifyAll()通常用于解決多線程之間的通信和協(xié)調(diào)問題。當(dāng)某個(gè)條件得到滿足時(shí),調(diào)用notifyAll()可以通知所有等待該條件的線程。
  • 謹(jǐn)慎使用:需要謹(jǐn)慎使用notifyAll(),因?yàn)閱拘阉芯€程可能會(huì)導(dǎo)致競爭和性能問題。在某些情況下,如果只有一個(gè)線程是合適的接收方,那么使用notify()來喚醒特定線程會(huì)更有效率。
  • 必須在同步塊中調(diào)用:就像notify()方法一樣,notifyAll()也必須在同步塊(synchronized塊)內(nèi)調(diào)用,以確保在對象上同步。通過同步塊,確保在調(diào)用notifyAll()時(shí),持有對象的鎖。
  • 競爭獲取鎖:被喚醒的線程會(huì)嘗試獲取對象的鎖,一旦獲得鎖,它們將從wait()方法返回,并開始競爭執(zhí)行。
  • 釋放鎖:調(diào)用notifyAll()并不會(huì)釋放對象鎖,它僅喚醒等待的線程,這些線程會(huì)在合適的時(shí)機(jī)爭奪鎖。

2.2.4 notify 使用場景

notify()的使用場景:

  • 單個(gè)喚醒:當(dāng)只需喚醒等待隊(duì)列中的一個(gè)線程時(shí),適合使用notify()。這種情況下,最多只有一個(gè)等待線程被喚醒,選擇被喚醒的線程是不確定的。
  • 資源更新:當(dāng)某個(gè)共享資源的狀態(tài)發(fā)生變化時(shí),并且只需要通知一個(gè)線程來處理這種變化時(shí),可以使用notify()。

notifyAll()的使用場景:

  • 多個(gè)喚醒:當(dāng)需要喚醒所有等待線程來處理某個(gè)共享資源的變化時(shí),應(yīng)該使用notifyAll()。這種情況下,所有等待線程都會(huì)被喚醒。
  • 條件變更:當(dāng)共享資源的狀態(tài)發(fā)生變化對多個(gè)線程都有影響時(shí),可以使用notifyAll()來通知所有等待線程,因?yàn)槎鄠€(gè)線程可能對資源的狀態(tài)變化做出不同的響應(yīng)。
  • 避免競爭問題:在某些情況下,使用notifyAll()可以避免因?yàn)橹粏拘岩粋€(gè)線程而導(dǎo)致的競爭問題,確保所有等待線程都能及時(shí)做出響應(yīng)。

2.2.5 notify 的執(zhí)行原理

notify()方法的執(zhí)行原理:

  • 當(dāng)一個(gè)線程調(diào)用對象的notify()方法時(shí),這個(gè)對象的監(jiān)視器被激活。
  • 在等待該對象的線程中,會(huì)有一個(gè)線程從等待隊(duì)列中被選中,進(jìn)入到鎖定狀態(tài),并嘗試重新獲取對象的鎖。
  • 一旦獲取到鎖,該線程會(huì)從wait()方法返回,并繼續(xù)執(zhí)行。
  • 其他等待該對象的線程仍然處于等待狀態(tài),需要重新競爭獲取對象的鎖來繼續(xù)執(zhí)行。

notifyAll()方法的執(zhí)行原理:

  • 當(dāng)一個(gè)線程調(diào)用對象的notifyAll()方法時(shí),所有等待該對象的線程將被喚醒。
  • 被喚醒的線程會(huì)一起競爭對象的鎖,以便能夠繼續(xù)執(zhí)行。
  • 每個(gè)被喚醒的線程嘗試重新獲取鎖,一旦成功獲取到鎖,它們會(huì)從wait()方法返回,并接著執(zhí)行后續(xù)代碼。

2.2.6 notify和notifyAll 注意事項(xiàng)和要點(diǎn):

  • 使用 notify和notifyAll 時(shí)需要先對調(diào)用的對象加鎖,否則會(huì)報(bào)錯(cuò)
  • notify()方法和notifyAll()方法必須在同步塊中(synchronized塊)調(diào)用,以確保在調(diào)用這些方法時(shí)對象的鎖處于正確狀態(tài)。
  • 被喚醒的線程在獲取到鎖并從wait()方法返回后,可能需要檢查等待期間的條件是否發(fā)生了變化,從而決定是否繼續(xù)執(zhí)行。

三、wait/nofity 經(jīng)典使用方式

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class WaitNotify {
    static boolean flag = true;
    static Object  lock = new Object();

    public static void main(String[] args) {
       Thread waitThread = new Thread(new Wait(), "waitThread");
       waitThread.start();
       try {
          TimeUnit.SECONDS.sleep(1);
       } catch (InterruptedException e) {
          e.printStackTrace();
       }

       new Thread(new Notify(), "notifyThread").start();


    }

//wait
    static class Wait implements Runnable {
       public void run() {
          synchronized (lock) {
             while (flag) {
                try {
                   System.out.println(Thread.currentThread() + " flag is true" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                   //沒有釋放資源 wait 等待
                   lock.wait();
                } catch (InterruptedException e) {
                }
             }
             System.out.println(Thread.currentThread() + " flag is false" + new SimpleDateFormat("HH:mm:ss").format(new Date()));

          }
       }
    }

    static class Notify implements Runnable {
       public void run() {
          synchronized (lock) {
             while (flag) {
                System.out.println(Thread.currentThread() + "hold lock  notify" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                //資源準(zhǔn)備
                好了,nofity
                lock.notifyAll();
                flag = false;
                try {
                   TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }

             }
          }
          synchronized (lock) {
             System.out.println(Thread.currentThread() + "hold lock again. notify" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
             try {
                TimeUnit.SECONDS.sleep(5);
             } catch (InterruptedException e) {
                e.printStackTrace();
             }

          }
       }
    }
}

這是最經(jīng)典的等待/通知的范式:但資源沒有準(zhǔn)備好時(shí),wait 等待,當(dāng)資源準(zhǔn)備好了,notify 通知。

四、總結(jié)

文章詳細(xì)講解了Java中waitnotify方法的使用方法和注意事項(xiàng),通過這些方法實(shí)現(xiàn)線程間的協(xié)調(diào)與通信,并列舉了常見的使用場景,如協(xié)調(diào)多個(gè)線程操作、實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型等。此外,文章還強(qiáng)調(diào)了waitnotify方法必須在同步塊中調(diào)用,以確保線程安全。

以上就是Java通過notify和wait實(shí)現(xiàn)線程間的通信功能的詳細(xì)內(nèi)容,更多關(guān)于Java notify wait線程通信的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java啟動(dòng)參數(shù)(-,?-X,?-XX參數(shù))的使用

    Java啟動(dòng)參數(shù)(-,?-X,?-XX參數(shù))的使用

    本文主要介紹了Java啟動(dòng)參數(shù)(-,?-X,?-XX參數(shù))的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java實(shí)現(xiàn)貪吃蛇大作戰(zhàn)小游戲的示例代碼

    Java實(shí)現(xiàn)貪吃蛇大作戰(zhàn)小游戲的示例代碼

    本文主要介紹了Java實(shí)現(xiàn)貪吃蛇大作戰(zhàn)小游戲的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java中日期的加減&String Date Calendar的相互轉(zhuǎn)換方式

    Java中日期的加減&String Date Calendar的相互轉(zhuǎn)換方式

    這篇文章主要介紹了Java中日期的加減&String Date Calendar的相互轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • SpringCloud Ribbon負(fù)載均衡實(shí)例解析

    SpringCloud Ribbon負(fù)載均衡實(shí)例解析

    這篇文章主要介紹了SpringCloud Ribbon負(fù)載均衡實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • springboot基于keytool實(shí)現(xiàn)https的雙向認(rèn)證示例教程

    springboot基于keytool實(shí)現(xiàn)https的雙向認(rèn)證示例教程

    這篇文章主要介紹了springboot基于keytool實(shí)現(xiàn)https的雙向認(rèn)證,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • MybatisPlus逆向工程的項(xiàng)目實(shí)踐

    MybatisPlus逆向工程的項(xiàng)目實(shí)踐

    Mybatis-Plus逆向工程,是MP官方提供的一款代碼生成器,可以自動(dòng)生成對應(yīng)的實(shí)體類、Mapper接口和配置文件,,本文主要介紹了MybatisPlus逆向工程的項(xiàng)目實(shí)踐,感興趣的可以了解一下
    2024-03-03
  • Intellij IDEA使用restclient測試的教程圖解

    Intellij IDEA使用restclient測試的教程圖解

    這篇文章主要介紹了Intellij IDEA使用restclient測試的教程圖解,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Java中如何模擬HTTP請求并驗(yàn)證功能

    Java中如何模擬HTTP請求并驗(yàn)證功能

    要模擬HTTP請求并驗(yàn)證功能,你可以使用Spring Boot提供的MockMvc工具,它允許我們在沒有實(shí)際啟動(dòng)HTTP服務(wù)器的情況下測試Spring MVC控制器,下面給大家分享如何模擬HTTP請求并驗(yàn)證功能,感興趣的朋友一起看看吧
    2024-05-05
  • Spring?boot?RedisTemplate?序列化服務(wù)化配置方式

    Spring?boot?RedisTemplate?序列化服務(wù)化配置方式

    這篇文章主要介紹了Springboot?RedisTemplate序列化服務(wù)化配置方式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • SpringCloud Eureka 服務(wù)注冊實(shí)現(xiàn)過程

    SpringCloud Eureka 服務(wù)注冊實(shí)現(xiàn)過程

    這篇文章主要介紹了SpringCloud Eureka 服務(wù)注冊實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10

最新評論

亳州市| 大洼县| 富裕县| 柘荣县| 芜湖市| 象山县| 茂名市| 腾冲县| 广灵县| 铁力市| 武穴市| 宁海县| 黔江区| 宣汉县| 柘城县| 乾安县| 晋中市| 泽普县| 阳信县| 乌苏市| 曲水县| 乌苏市| 阿坝| 高雄县| 靖边县| 名山县| 黄平县| 本溪市| 紫云| 余江县| 大邑县| 峨山| 商河县| 新津县| 沂南县| 贵州省| 和硕县| 合水县| 弥渡县| 龙陵县| 象山县|