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

Java中wait()和notify()的正確使用方式

 更新時間:2026年03月23日 09:54:09   作者:yingjuxia.com  
本文詳細(xì)介紹了Java中wait()和notify()方法的作用,包括讓線程阻塞并釋放鎖、喚醒等待線程等,通過實(shí)例演示了它們在多線程同步中的應(yīng)用,,需要的朋友可以參考下

wait()、notify()notifyAll()Object 類 的原生方法,是 Java 最早提供的線程間協(xié)作機(jī)制(屬于低級別重量級的等待/通知機(jī)制)。

核心規(guī)則(必須全部記住,否則 100% 會出問題)

必須在 synchronized 塊/方法中調(diào)用

  • wait()、notify()、notifyAll() 都要求當(dāng)前線程持有同一個對象的監(jiān)視器鎖(monitor)
  • 否則拋出 IllegalMonitorStateException

wait() 會釋放鎖

  • 調(diào)用 wait() 后,當(dāng)前線程會釋放對象鎖,進(jìn)入該對象的等待隊(duì)列(wait set)

notify() / notifyAll() 不釋放鎖

  • 只是喚醒等待隊(duì)列中的一個/全部線程,但不立即把鎖給被喚醒的線程
  • 只有當(dāng)前持有鎖的線程離開 synchronized 塊后,被喚醒的線程才有機(jī)會競爭鎖

最經(jīng)典的寫法模板(生產(chǎn)級必須這樣寫)

// 消費(fèi)者
synchronized (lock) {
    while (conditionNotMet) {           // 必須用 while,不是 if?。ǚ乐固摷賳拘眩?
        lock.wait();                    // 釋放鎖并等待
    }
    // 條件滿足,消費(fèi)
    doConsume();
}

// 生產(chǎn)者
synchronized (lock) {
    // 生產(chǎn)
    doProduce();
    lock.notify();          // 或 notifyAll()
    // 離開 synchronized 塊后,被喚醒的線程才有機(jī)會搶鎖
}

為什么必須用 while 而不是 if?(虛假喚醒經(jīng)典坑)

虛假喚醒(spurious wakeup):線程可能在沒有被 notify 的情況下被系統(tǒng)喚醒(極少見,但 JVM 規(guī)范允許)。

// 錯誤寫法(極易出問題)
if (queue.isEmpty()) {
    lock.wait();   // 被虛假喚醒后,可能直接往下執(zhí)行,而隊(duì)列還是空的
}

// 正確寫法(生產(chǎn)環(huán)境唯一推薦)
while (queue.isEmpty()) {
    lock.wait();
}

完整經(jīng)典示例:生產(chǎn)者-消費(fèi)者(固定大小隊(duì)列)

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumer {

    private final Queue<Integer> queue = new LinkedList<>();
    private final int MAX_SIZE = 10;
    private final Object lock = new Object();

    class Producer implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    synchronized (lock) {
                        while (queue.size() == MAX_SIZE) {
                            System.out.println("隊(duì)列已滿,生產(chǎn)者等待...");
                            lock.wait();
                        }
                        int item = (int) (Math.random() * 100);
                        queue.offer(item);
                        System.out.println("生產(chǎn): " + item + ",當(dāng)前大小: " + queue.size());
                        lock.notifyAll();  // 喚醒所有等待的消費(fèi)者
                    }
                    Thread.sleep(500); // 模擬生產(chǎn)耗時
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    synchronized (lock) {
                        while (queue.isEmpty()) {
                            System.out.println("隊(duì)列為空,消費(fèi)者等待...");
                            lock.wait();
                        }
                        int item = queue.poll();
                        System.out.println("消費(fèi): " + item + ",當(dāng)前大小: " + queue.size());
                        lock.notifyAll();  // 喚醒可能等待的生產(chǎn)者
                    }
                    Thread.sleep(800); // 模擬消費(fèi)耗時
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();
        new Thread(pc.new Producer(), "生產(chǎn)者-1").start();
        new Thread(pc.new Consumer(), "消費(fèi)者-1").start();
        new Thread(pc.new Consumer(), "消費(fèi)者-2").start();
    }
}

常見錯誤寫法匯總(你幾乎一定會踩)

錯誤寫法后果正確做法
在 synchronized 外面調(diào)用 wait()IllegalMonitorStateException必須在 synchronized 內(nèi)
用 if 判斷條件而不是 while虛假喚醒導(dǎo)致邏輯錯誤永遠(yuǎn)用 while
只用 notify() 而不用 notifyAll()可能導(dǎo)致部分線程永久等待(信號丟失)多消費(fèi)者/生產(chǎn)者場景用 notifyAll
notify() 后立即修改共享變量可能導(dǎo)致被喚醒線程看到舊狀態(tài)修改完再 notify
不同對象上 wait/notify線程永遠(yuǎn)喚不醒必須用同一個鎖對象

2025–2026 年真實(shí)項(xiàng)目中的選擇建議

場景推薦工具原因
簡單生產(chǎn)者-消費(fèi)者、線程間狀態(tài)等待wait/notify輕量、無額外依賴
需要超時等待Condition.await(long, TimeUnit)ReentrantLock 的 Condition 更靈活
大多數(shù)現(xiàn)代業(yè)務(wù)代碼BlockingQueue(ArrayBlockingQueue)封裝好了 wait/notify,API 更安全
高并發(fā)、復(fù)雜條件等待Condition + ReentrantLock支持多個等待隊(duì)列、公平鎖、可中斷
響應(yīng)式/異步場景CompletableFuture / reactor基本不再用原始 wait/notify

一句話總結(jié)(面試/生產(chǎn)最常問的答案):

“wait() 和 notify() 必須在同一個對象的 synchronized 塊中使用,wait() 會釋放鎖并進(jìn)入等待隊(duì)列,notify() 只喚醒但不釋放鎖,永遠(yuǎn)用 while 判斷條件,多線程協(xié)作場景優(yōu)先考慮 notifyAll()。”

以上就是Java中wait()和notify()的正確使用方式的詳細(xì)內(nèi)容,更多關(guān)于Java使用wait()和notify()的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中LinkedList的模擬實(shí)現(xiàn)

    Java中LinkedList的模擬實(shí)現(xiàn)

    本文主要介紹了Java中LinkedList的模擬實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Spring?Boot指定外部配置文件簡單示例

    Spring?Boot指定外部配置文件簡單示例

    Spring Boot可以讓你將配置外部化,這樣你就可以在不同的環(huán)境中使用相同的應(yīng)用程序代碼,這篇文章主要給大家介紹了關(guān)于Spring?Boot指定外部配置文件的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • IntelliJ IDEA中加速M(fèi)aven編譯的終極指南

    IntelliJ IDEA中加速M(fèi)aven編譯的終極指南

    這篇文章主要為大家詳細(xì)介紹了IntelliJ IDEA中加速M(fèi)aven編譯的終極指南,從 7 分鐘提速到 30 秒,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2025-10-10
  • Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析

    Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析

    這篇文章主要介紹了Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Springboot整合Netty實(shí)現(xiàn)RPC服務(wù)器的示例代碼

    Springboot整合Netty實(shí)現(xiàn)RPC服務(wù)器的示例代碼

    這篇文章主要介紹了Springboot整合Netty實(shí)現(xiàn)RPC服務(wù)器的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Python如何使用@property @x.setter及@x.deleter

    Python如何使用@property @x.setter及@x.deleter

    這篇文章主要介紹了Python如何使用@property @x.setter及@x.deleter,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Java數(shù)學(xué)工具類MathUtil詳解

    Java數(shù)學(xué)工具類MathUtil詳解

    這篇文章主要為大家詳細(xì)介紹了Java數(shù)學(xué)工具類MathUtil的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 深入淺析Java 抽象類和接口

    深入淺析Java 抽象類和接口

    這篇文章主要介紹了Java 抽象類和接口的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • Java 使用Socket正確讀取數(shù)據(jù)姿勢

    Java 使用Socket正確讀取數(shù)據(jù)姿勢

    這篇文章主要介紹了Java 使用Socket正確讀取數(shù)據(jù)姿勢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • javax.servlet不存在的解決辦法

    javax.servlet不存在的解決辦法

    今天在關(guān)于servlet的編譯中出現(xiàn)了一下小小的錯誤,發(fā)現(xiàn)javax.servlet不存在,本文就介紹一下解決方法,感興趣的可以了解一下
    2021-07-07

最新評論

临颍县| 云浮市| 柳河县| 乌拉特前旗| 连城县| 密云县| 崇左市| 樟树市| 南澳县| 新龙县| 若羌县| 柘荣县| 长丰县| 临夏县| 张家港市| 滁州市| 江津市| 赫章县| 罗田县| 濮阳县| 古交市| 山阳县| 都安| 南汇区| 多伦县| 西乡县| 迁安市| 广元市| 丰城市| 沙雅县| 静安区| 聂拉木县| 康定县| 鄂托克旗| 莎车县| 海安县| 遂宁市| 丰台区| 桐庐县| 潢川县| 太湖县|