線程的等待與喚醒機制--生產者與消費者代碼實現

包子類(鎖對象)
包子鋪類(生產者)
吃貨類(消費者)

簡單描述:
剛剛開始的包子狀態是沒有(即沒有包子),所以喚醒包子鋪線程去生產包子,生產完包子後,修改包子狀態爲有,喚醒吃貨線程去吃包子,包子鋪線程進入等待狀態;吃貨吃完包子後,修改包子狀態爲沒有,喚醒包子鋪線程,吃貨線程進入等待狀態。爲了保證線程安全,使用了同步代碼塊,用包子類作爲鎖對象。

while(true){}
無限循環,讓包子鋪一直生產包子,吃貨一直吃包子。

BaoZi.java

public class BaoZi {
    // 皮
    String pi;
    // 餡
    String xian;
    // 包子的狀態:有 true ,沒有 false ,設置初始值爲 false 沒有包自
    boolean flag = false;
}

BaoZiPu.java

public class BaoZiPu extends Thread{
    // 需要在成員位置創建一個包子變量
    private BaoZi bz;

    // 使用帶參數構造方法,爲這個包子變量附值
    public BaoZiPu(BaoZi bz){
        this.bz = bz;
    }

    // 設置線程任務(run):生產包子
    @Override
    public void run() {
        // 定義一個變量
        int count = 0;
        while(true) {
            // 必須同時同步技術保證兩個線程只能一個在執行
            synchronized (bz) {
                // 對包子的狀態進行判斷
                if (bz.flag == true) {
                    // 包子鋪調用 wait 方法進入等待狀態
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 被喚醒在之後執行,包子鋪生產包子
                // 增加一些趣味性:交替生產兩種包子
                if (count % 2 == 0) {
                    // 生產 薄皮三鮮餡包子
                    bz.pi = "薄皮";
                    bz.xian = "三鮮餡";
                } else {
                    // 生產 冰皮牛肉大蔥包子
                    bz.pi = "冰皮";
                    bz.xian = "牛肉大蔥";
                }
                count++;
                System.out.println("包子鋪正在生產:" + bz.pi + bz.xian + "包子");
                // 生產包子需要3秒鐘
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 包子鋪生產好了包子
                // 修改包子的狀態爲 true 有
                bz.flag = true;
                // 喚醒吃貨線程,讓吃貨線程吃包子
                bz.notify();
                System.out.println("包子鋪已經生產:" + bz.pi + bz.xian + "包子,吃貨可以開始吃");
            }
        }
    }
}

ChiHuo.java

public class ChiHuo extends Thread{

    // 需要在成員位置創建一個包子變量
    private BaoZi bz;

    // 使用帶參數構造方法,爲這個包子變量附值
    public ChiHuo(BaoZi bz){
        this.bz = bz;
    }

    // 設置線程任務(run):吃包子
    @Override
    public void run() {
        // 使用死循環,讓吃貨一直吃包子
        while(true){
            // 必須同時同步技術保證兩個線程只能一個在執行
            synchronized(bz){
                // 對包子的狀態進行判斷
                if (bz.flag == false){
                    // 吃貨調用 wait 方法進入等待狀態
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 被喚醒之後執行的代碼,吃包子
                System.out.println("吃貨正在吃:"+bz.pi+bz.xian+"包子");
                // 吃貨吃完包子
                // 修改包子的狀態爲 false 沒有
                bz.flag = false;
                // 吃貨喚醒包子鋪線程,生產包子
                bz.notify();
                System.out.println("吃貨已經把:"+bz.pi+bz.xian+"的包子吃完了,包子鋪開始生產包子");
                System.out.println("-----------------------------");
            }
        }
    }
}

DemoTest.java

public class DemoTest {
    public static void main(String[] args) {
        System.out.println("-------");
        BaoZi bz = new BaoZi();
        // 創建包子鋪線程,開啓,生產包子
        new BaoZiPu(bz).start();
        // 創建吃貨線程,開啓,吃包子
        new ChiHuo(bz).start();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章