Java學習日誌(十二): 線程狀態,等待與喚醒案例

JavaEE學習日誌持續更新----> 必看!JavaEE學習路線(文章總彙)

線程狀態

在API中 java.lang.Thread.State 這個枚舉中給出了六種線程狀態:

線程狀態 導致狀態發生條件
NEW(新建) 線程剛被創建,但是並未啓動。還沒調用start方法。
Runnable(可運行) 線程可以在java虛擬機中運行的狀態,可能正在運行自己代碼,也可能沒有,這取決於操作系統處理器。
Blocked(鎖阻塞) 當一個線程試圖獲取一個對象鎖,而該對象鎖被其他的線程持有,則該線程進入Blocked狀態;當該線程持有鎖時,該線程將變成Runnable狀態。
Waiting(無限等待) 一個線程在等待另一個線程執行一個(喚醒)動作時,該線程進入Waiting狀態。進入這個狀態後是不能自動喚醒的,必須等待另一個線程調用notify或者notifyAll方法才能夠喚醒。
Timed Waiting(計時等待) 同waiting狀態,有幾個方法有超時參數,調用他們將進入Timed Waiting狀態。這一狀態將一直保持到超時期滿或者接收到喚醒通知。帶有超時參數的常用方法有Thread.sleep 、 Object.wait。
Teminated(被 終止) 因爲run方法正常退出而死亡,或者因爲沒有捕獲的異常終止了run方法而死亡。

在這裏插入圖片描述

等待與喚醒案例(包子鋪案例)

等待與喚醒:線程之間的通信
Object類中的方法

  • void wait() 導致當前線程等待它被喚醒,通常是通知或中斷 。
  • void notify() 喚醒正在此對象監視器(對象鎖)上等待的單個線程。

注意:

  1. wait和notify方法必須由鎖對象調用(必須是同個鎖對象
    鎖對象–>wait() 鎖對象–>notify()
  2. wait和notify方法一般寫在同步中

案例:包子鋪案例

需求
兩大線程:設線程A(包子鋪),執行生產包子的動作。線程B(吃貨),執行吃包子的操作

共享資源:包子

執行動作:生產一個包子,吃一個包子

分析
包子的狀態進行分析
沒有包子:吃貨線程喚醒包子鋪線程—>吃貨線程等待—>包子鋪線程做包子—>包子鋪做好包子—>修改包子的狀態—>有包子
有包子:包子鋪喚醒吃貨線程—>包子鋪線程等待—>吃貨吃包子—>修改包子的狀態—>沒有包子
…(循環)

代碼實現:

資源類:包子,其中有皮,陷,包子的狀態

public class BaoZi {
    String pi;
    String xian;
    //包子狀態,初始值爲false,沒有包子
    boolean flag = false;
}

包子鋪類:是一個線程類,線程任務:生產包子

對包子的狀態進行判斷:
true:有包子
        包子鋪線程調用wait等待
false:沒有包子
        包子鋪線程生產包子
        生產x皮x陷的包子
        生產包子花費3秒
        生產完包子,修改包子狀態爲true
        包子鋪線程喚醒吃貨線程,吃包子

注意:

  1. 生產包子和吃包子,只能有一個在執行,需要使用同步技術
  2. 同步技術需要使用鎖對象,可以使用包子對象
    在成員位置創建一個包子對象
    使用構造方法爲包子變量賦值
public class BaoZiPu implements Runnable {
    //在成員位置創建一個包子對象
    BaoZi bz;
    //使用構造方法爲包子變量賦值
    public BaoZiPu(BaoZi bz) {
        this.bz = bz;
    }

    //線程任務:生產包子
    @Override
    public void run() {
        while(true){
/*
            1.生產包子和吃包子,只能有一個在執行,需要使用同步技術
            2.同步技術需要使用鎖對象,可以使用包子對象
         */
            synchronized (bz){
                //對包子狀態進行判斷
                if(bz.flag==true){
                    //true:有包子
                    //            包子鋪線程調用wait等待
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //包子鋪被吃貨喚醒之後執行的代碼
                //false:沒有包子,包子鋪線程生產包子
                //生產x皮x陷的包子
                bz.pi = "薄皮";
                bz.xian = "玉米鮮肉";
                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+"的包子!");
            }
        }
    }
}

吃貨類:是一個線程類,線程任務:吃包子

對包子的狀態進行判斷:
false:沒有包子
    吃貨線程調用wait等待
true:有包子
    吃貨線程開始吃包子
    打印吃x皮x陷的包子
    吃完包子,修改包子的狀態爲false
    吃貨線程喚醒包子鋪線程,做包子

注意:

  1. 生產包子和吃包子,只能有一個在執行,需要使用同步技術
  2. 同步技術需要使用鎖對象,可以使用包子對象
    在成員位置創建一個包子對象
    使用構造方法爲包子變量賦值
public class ChiHuo implements Runnable{
    //在成員位置創建一個包子對象
    BaoZi bz;
    //使用構造方法爲包子變量賦值
    public ChiHuo(BaoZi bz) {
        this.bz = bz;
    }

    //線程任務:吃包子
    @Override
    public void run() {
        while (true){
            /*
            1.生產包子和吃包子,只能有一個在執行,需要使用同步技術
            2.同步技術需要使用鎖對象,可以使用包子對象
         */
            synchronized (bz){
                //對包子的狀態進行判斷
                //        false:沒有包子
                if (bz.flag==false){
                    //吃貨線程調用wait等待
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            /*
                吃貨線程被包子鋪線程喚醒之後執行的代碼
             */
                //true:有包子,吃貨線程開始吃包子
                //打印吃x皮x陷的包子
                System.out.println("吃貨正在吃"+bz.pi+bz.xian+"的包子!");
                //吃完包子,修改包子的狀態爲false
                bz.flag = false;
                //吃貨線程喚醒包子鋪線程,做包子
                bz.notify();
                System.out.println("吃貨已經吃完了"+bz.pi+bz.xian+"的包子!包子鋪趕緊生產包子!");
                System.out.println("-----------------------");
            }
        }
    }
}

測試類
創建一個包子對象
創建一個包子鋪線程,生產包子
創建一個吃貨線程,吃包子

public class Demo01 {
    public static void main(String[] args) {
        //創建一個包子對象
        BaoZi bz = new BaoZi();
        //創建一個包子鋪線程,生產包子
        new Thread(new BaoZiPu(bz)).start();
        //創建一個吃貨線程,吃包子
        new Thread(new ChiHuo(bz)).start();
    }
}

運行結果:

包子鋪正在生產薄皮玉米鮮肉的包子!
包子鋪已經生產好薄皮玉米鮮肉的包子!
吃貨正在吃薄皮玉米鮮肉的包子!
吃貨已經吃完了薄皮玉米鮮肉的包子!包子鋪趕緊生產包子!
-----------------------
包子鋪正在生產薄皮玉米鮮肉的包子!
包子鋪已經生產好薄皮玉米鮮肉的包子!
吃貨正在吃薄皮玉米鮮肉的包子!
吃貨已經吃完了薄皮玉米鮮肉的包子!包子鋪趕緊生產包子!
-----------------------
...
發佈了25 篇原創文章 · 獲贊 33 · 訪問量 5962
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章