java複習第6天---多線程----6.4--多線程等待喚醒機制

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、案例

  • 問題描述:

    1. 包子鋪生產包子,喫貨喫包子
    2. 包子有屬性皮、陷 和一個描述有無的狀態
    3. 當有包子的時候,包子鋪提醒喫貨喫包子,且包子鋪wait;喫貨喫包子,且設置包子狀態:無,提醒包子鋪生產包子
    4. 當沒有的包子的時候,包子鋪生成包子
    5. 重複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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章