java複習第6天---多線程----6.4--多線程等待喚醒機制
目錄
內容
1、線程狀態
線程具有生命週期,從重建到消亡。java.lang.Thread.State這個枚舉中給出來線程的六種狀態。線程狀態轉換圖示1-1:
- 解析:
線程狀態 | 導致狀態發生的條件 |
---|---|
NEW | 線程別創建,但是沒有調用 start 方法 |
Runnable(可運行狀態) | 線程在JVM中可運行的狀態 |
Blocked(阻塞狀態) | 當一個線程對象,試圖獲取鎖對象,但是該鎖對象被其他線程佔用時,次線程進入Bolcked狀態;當該線程獲取到鎖對象時,進入Runnable狀態 |
Waiting(無限等待狀態) | 一個線程等待另外一個線程(喚醒)時,進入Waiting狀態,不能自動喚醒,必須等待另外一個線程執行notify或者notifyAll方法才能夠喚醒 |
Timed-Waiting(計時等待狀態) | 同waiting,有幾個方法有超時參數,當被調用時,進入Timed-Waiting狀態。狀態一直持續到朝時期滿或者被喚醒。常用有超時參數的方法 Threa.sleep,Object wait |
Terminated(死亡狀態) | run方法正常結束或者掉用stop方法 |
-
Timed-Waiting示例1-1:每隔一秒打印一個數字
package thread.create; public class TestTimedWaitng { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for(int i = 0; i <= 10; i++) { System.out.println(i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } 測試結果:自己測試纔有效果
2、線程間通信
- 線程間通信:當多線程處理同一資源,但是任務不同時,那麼線程間存在通信問題。
- 爲什麼線程間需要處理通信問題:多線程併發執行,CPU默認隨機切換執行線程;當需要多個線程共同處理資源時,但是執行不同的任務,並且有序執行,以此高效率的完成任務。
- 怎麼保證多線程間通信有效利用資源:需要用到下面要學的等待喚醒機制
2、線程等待喚醒機制
2.1、概述
等待喚醒是線程間協助機制。線程間存在競爭,比如爭奪鎖;線程間存在協助機制,以共同完成任務。比如,公司同事間升職競爭,但是更多時候,需要同事共同協助完成某個項目。
線程執行wait方法,進入waiting狀態。等待其他線程完成指定的代碼後,執行notify將其喚醒。當多個線程等待時,如需要,可以執行notifyAll方法,把所有等待的線程喚醒。
wait/notify就是等待喚醒機制。
2.2、使用方法
- wait:不在活動,不在參與調度。不佔用CUP資源,不參與競爭。這時線程狀態Waiting。它需要其他線程執行一個特別的操作,notify(通知)在這個對象上等待的線程從wait set中釋放(即喚醒),重寫進入調度隊列
- notify:選取所通知對象上wait set 中的一個線程釋放
- notifyAll:選取所通知對象上wait set 中的所有線程釋放
2.3、案例
-
問題描述:
- 包子鋪生產包子,喫貨喫包子
- 包子有屬性皮、陷 和一個描述有無的狀態
- 當有包子的時候,包子鋪提醒喫貨喫包子,且包子鋪wait;喫貨喫包子,且設置包子狀態:無,提醒包子鋪生產包子
- 當沒有的包子的時候,包子鋪生成包子
- 重複3,4步驟
-
分析
-
包子類:
- 屬性:皮、陷,flag
-
包子鋪線程:
- 屬性:包子對象引用
- 構造方法:傳入包子對象
- 方法:重寫線程run方法生成包子
-
喫貨線程:
- 屬性:包子對象引用
- 構造方法:傳入包子對象
- 方法:重寫線程run方法喫包子
-
-
代碼2.3-1
package thread.notifyAndWait; public class Baozi { private String pi; private String xian; private boolean flag = false; public Baozi(String pi, String xian) { this.pi = pi; this.xian = xian; } public Baozi() { } @Override public String toString() { return "Baozi [pi=" + pi + ", xian=" + xian + "]"; } public String getPi() { return pi; } public void setPi(String pi) { this.pi = pi; } public String getXian() { return xian; } public void setXian(String xian) { this.xian = xian; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } } package thread.notifyAndWait; public class Baozipu extends Thread{ Baozi baozi; public Baozipu(Baozi baozi) { this.baozi = baozi; } @Override public void run() { int count = 0; while(true) { synchronized(baozi) { if(baozi.isFlag()) { try { baozi.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else { if((count & 1) == 0) { baozi.setPi("薄皮"); baozi.setXian("三鮮餡"); }else { baozi.setPi("冰皮"); baozi.setXian("羊肉餡"); } count++; System.out.println("包子鋪正在生產:" + baozi); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("包子鋪已經生產:" + baozi); baozi.setFlag(true); baozi.notify(); } } } } } package thread.notifyAndWait; public class Chihuo extends Thread{ Baozi baozi; public Chihuo(Baozi baozi) { this.baozi = baozi; } @Override public void run() { while(true) { synchronized(baozi) { if(baozi.isFlag()) { System.out.println("喫貨正在喫:" + baozi); baozi.setFlag(false); System.out.println("喫貨已經喫完:" + baozi); baozi.notify(); }else { try { baozi.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } } package thread.notifyAndWait; public class TestNotifyAndWait { public static void main(String[] args) { Baozi baozi = new Baozi(); new Baozipu(baozi).start(); new Chihuo(baozi).start(); } } 測試結果: 包子鋪正在生產:Baozi [pi=薄皮, xian=三鮮餡] 包子鋪已經生產:Baozi [pi=薄皮, xian=三鮮餡] 喫貨正在喫:Baozi [pi=薄皮, xian=三鮮餡] 喫貨已經喫完:Baozi [pi=薄皮, xian=三鮮餡] 包子鋪正在生產:Baozi [pi=冰皮, xian=羊肉餡] 包子鋪已經生產:Baozi [pi=冰皮, xian=羊肉餡] 喫貨正在喫:Baozi [pi=冰皮, xian=羊肉餡] 喫貨已經喫完:Baozi [pi=冰皮, xian=羊肉餡]
後記 :
本項目爲參考某馬視頻開發,相關視頻及配套資料可自行度娘或者聯繫本人。上面爲自己編寫的開發文檔,持續更新。歡迎交流,本人QQ:806797785
前端項目源代碼地址:https://gitee.com/gaogzhen/vue-leyou
後端JAVA源代碼地址:https://gitee.com/gaogzhen/JAVA