欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java生產(chǎn)者和消費(fèi)者實(shí)現(xiàn)等待喚醒機(jī)制

 更新時(shí)間:2025年06月05日 09:54:21   作者:寶耶  
本文主要介紹了Java生產(chǎn)者和消費(fèi)者實(shí)現(xiàn)等待喚醒機(jī)制,通過(guò)synchronized、wait()和notifyAll()實(shí)現(xiàn)線程間的安全協(xié)作,具有一定的參考價(jià)值,感興趣的可以了解一下

本文將介紹如何使用Java多線程實(shí)現(xiàn)經(jīng)典的生產(chǎn)者-消費(fèi)者模型,通過(guò)synchronized、wait()和notifyAll()實(shí)現(xiàn)線程間的安全協(xié)作。

模型概述

生產(chǎn)者-消費(fèi)者模型是多線程編程中的經(jīng)典案例,主要解決以下問(wèn)題:

  • 生產(chǎn)者線程負(fù)責(zé)生產(chǎn)數(shù)據(jù)/資源
  • 消費(fèi)者線程負(fù)責(zé)消費(fèi)數(shù)據(jù)/資源
  • 生產(chǎn)者和消費(fèi)者通過(guò)共享緩沖區(qū)進(jìn)行通信
  • 需要解決線程同步和資源競(jìng)爭(zhēng)問(wèn)題

完整代碼實(shí)現(xiàn)

1. Desk.java(共享數(shù)據(jù)類)

/**
 * 共享數(shù)據(jù)類
 * - foodflag: 食物狀態(tài)標(biāo)記(0=無(wú)食物,1=有食物)
 * - count: 剩余食物數(shù)量
 * - lock: 同步鎖對(duì)象
 */
public class Desk {
    public static int foodflag = 0;
    public static int count = 10;
    public static final Object lock = new Object();
}

2. Cook.java(生產(chǎn)者線程)

/**
 * 生產(chǎn)者線程 - 廚師
 */
public class Cook extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (Desk.lock) {
                // 如果食物已全部生產(chǎn)完成,則退出
                if (Desk.count == 0) {
                    break;
                }
                
                // 如果還有食物未被消費(fèi),則等待
                if (Desk.foodflag == 1) {
                    try {
                        Desk.lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 生產(chǎn)食物
                    System.out.println(Thread.currentThread().getName() + " 做了一碗面");
                    Desk.foodflag = 1;
                    // 通知消費(fèi)者可以消費(fèi)了
                    Desk.lock.notifyAll();
                }
            }
        }
        System.out.println(Thread.currentThread().getName() + " 停止生產(chǎn)");
    }
}

3. Foodie.java(消費(fèi)者線程)

/**
 * 消費(fèi)者線程 - 吃貨
 */
public class Foodie extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (Desk.lock) {
                // 如果食物已全部消費(fèi)完,則退出
                if (Desk.count == 0) {
                    Desk.lock.notifyAll();  // 確保生產(chǎn)者線程能退出
                    break;
                }
                
                // 如果沒(méi)有食物,則等待
                if (Desk.foodflag == 0) {
                    try {
                        Desk.lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 消費(fèi)食物
                    Desk.count--;
                    System.out.println(Thread.currentThread().getName() + " 吃了一碗,還剩 " + Desk.count + " 碗");
                    Desk.foodflag = 0;
                    // 通知生產(chǎn)者可以生產(chǎn)了
                    Desk.lock.notifyAll();
                }
            }
        }
        System.out.println(Thread.currentThread().getName() + " 停止消費(fèi)");
    }
}

4. Main.java(測(cè)試類)

/**
 * 測(cè)試類
 */
public class Main {
    public static void main(String[] args) {
        // 創(chuàng)建并啟動(dòng)生產(chǎn)者線程
        Cook cook = new Cook();
        cook.setName("廚師");
        
        // 創(chuàng)建并啟動(dòng)消費(fèi)者線程
        Foodie foodie = new Foodie();
        foodie.setName("吃貨");
        
        cook.start();
        foodie.start();
    }
}

關(guān)鍵點(diǎn)解析

1. 同步機(jī)制

我們使用synchronized關(guān)鍵字實(shí)現(xiàn)對(duì)共享資源的互斥訪問(wèn):

synchronized (Desk.lock) {
    // 臨界區(qū)代碼
}

2. 線程通信

通過(guò)wait()notifyAll()實(shí)現(xiàn)線程間協(xié)作:

  • wait():釋放鎖并進(jìn)入等待狀態(tài)

  • notifyAll():?jiǎn)拘阉械却撴i的線程

3. 生產(chǎn)消費(fèi)邏輯

  • 生產(chǎn)者檢查foodflag

    • 為0時(shí)生產(chǎn)食物并設(shè)置foodflag=1

    • 為1時(shí)等待消費(fèi)者消費(fèi)

  • 消費(fèi)者檢查foodflag

    • 為1時(shí)消費(fèi)食物并設(shè)置foodflag=0

    • 為0時(shí)等待生產(chǎn)者生產(chǎn)

執(zhí)行結(jié)果示例

廚師 做了一碗面
吃貨 吃了一碗,還剩 9 碗
廚師 做了一碗面
吃貨 吃了一碗,還剩 8 碗
...
吃貨 吃了一碗,還剩 0 碗
廚師 停止生產(chǎn)
吃貨 停止消費(fèi)

常見(jiàn)問(wèn)題解答

Q1: 為什么使用notifyAll()而不是notify()?

notifyAll()會(huì)喚醒所有等待線程,讓它們公平競(jìng)爭(zhēng)鎖,避免某些線程長(zhǎng)期得不到執(zhí)行的情況。而notify()只隨機(jī)喚醒一個(gè)線程,可能導(dǎo)致線程饑餓。

Q2: 為什么要在finally塊外調(diào)用notifyAll()?

因?yàn)閚otifyAll()必須在持有鎖的情況下調(diào)用,而synchronized塊結(jié)束時(shí)鎖會(huì)自動(dòng)釋放,所以不需要在finally中調(diào)用。

Q3: 如何避免死鎖?

  • 確保每個(gè)wait()都有對(duì)應(yīng)的notifyAll()

  • 設(shè)置合理的退出條件(如count == 0

  • 避免嵌套鎖

總結(jié)

通過(guò)這個(gè)案例,我們學(xué)習(xí)了:

  • 如何使用synchronized實(shí)現(xiàn)線程同步

  • 如何使用wait()/notifyAll()實(shí)現(xiàn)線程通信

  • 生產(chǎn)者-消費(fèi)者模型的經(jīng)典實(shí)現(xiàn)

  • 多線程編程中的常見(jiàn)問(wèn)題及解決方案

這個(gè)模型可以應(yīng)用于許多實(shí)際場(chǎng)景,如消息隊(duì)列、任務(wù)調(diào)度等系統(tǒng)設(shè)計(jì)中。

到此這篇關(guān)于Java生產(chǎn)者和消費(fèi)者實(shí)現(xiàn)等待喚醒機(jī)制的文章就介紹到這了,更多相關(guān)Java 等待喚醒機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論