執行緒通信問題
執行緒通信
-
應用場景:生產者和消費者的問題
- 假設倉庫中只能存放一件產品,生產者將生產出來的產品放入倉庫,消費者將倉庫中產品取走消費,
- 如果倉庫中沒有產品,則生產者將產品放入倉庫,否則停止生產并等待,直到倉庫中的產品被消費者取走為止,
- 如果倉庫中放有產品,則消費者可以將產品取走消費,否則停止消費并等待,直到倉庫中再次放入產品為止,
-
Java提供了幾個方法解決執行緒之間的通信問題
方法名 作用 wait() 表示執行緒一直等待,直到其他執行緒通知,與sleep不同,會釋放鎖 wait(long timeout) 指定等待的毫秒數 notify() 喚醒一個處于等待狀態的執行緒 notifyAll() 喚醒聽一個物件上所有呼叫wait()方法的執行緒,優先級別高的執行緒優先調度 注意:均是Object類的方法,都只能在同步方法或者同步代碼塊中使用,否則會拋出例外IIIegaIMonitorStateException
分析
這是一個執行緒同步問題,生產者和消費者共享同一個資源,并且生產者和消費者之間相互依賴,互為條件,
- 對于生產者,沒有生產產品之前,要通知消費者等待,而生產了產品之后,又需要馬上通知消費者消費,
- 對于消費者,在消費之后,要通知生產者已經結束消費,需要生成新的產品以供消費,
- 在生產者消費者問題中,僅有synchronized是不夠的
- synchronized可阻止并發更新同一個共享資源,實作了同步
- synchronized不能用來實作不同執行緒之間的資訊傳遞(通信)
解決方式1
并發協作模型“生產者/消費者模式”——>管程法
- 生產者:負責生產資料的模塊(可能是方法、物件、執行緒、行程);
- 消費者:負責處理資料的模塊(可能是方法、物件、執行緒、行程);
- 緩沖區:消費者不能直接使用生產者的資料,他們之間有個“緩沖區”
生產者將生產好的資料放入緩沖區,消費者從緩沖區拿出資料
-
舉例:
// 測驗:生產者消費者模型-->利用緩沖區解決:管程法 // 生產者,消費者,產品,緩沖區 public class TestPC { public static void main(String[] args) { SynContainer container = new SynContainer(); new Productor(container).start(); new Consumer(container).start(); } } // 生產者 class Productor extends Thread{ SynContainer container; public Productor(SynContainer container){ this.container = container; } // 生產 @Override public void run() { for (int i = 0; i < 100; i++) { container.push(new Chicken(i)); System.out.println("生產了"+i+"只雞"); } } } // 消費者 class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container){ this.container = container; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消費了-->"+container.pop().id+"只雞"); } } } // 產品 class Chicken{ int id;// 產品編號 public Chicken(int id){ this.id = id; } } // 緩沖區 class SynContainer{ // 需要一個容器大小 Chicken[] chickens = new Chicken[10]; // 容器計算器 int count = 0; // 生產者放入產品 public synchronized void push(Chicken chicken){ // 如果容器滿了,就需要等待消費產品 if(count==chickens.length){ // 通知消費者消費,生產等待 try { //導致當前執行緒等待,直到另一個執行緒呼叫該物件的 notify()方法或 notifyAll()方法, this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 如果沒有滿,我們就需要丟入產品 chickens[count] = chicken; count++; // 可以通知消費者消費了 this.notifyAll(); // notifyAll喚醒正在等待物件監視器的所有執行緒, } // 消費者消費產品 public synchronized Chicken pop(){ // 判斷能否消費 if (count == 0){ // 等待生產者生產,消費者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 如果可以消費 count--; Chicken chicken = chickens[count]; // 吃完了,通知生產者生產 return chicken; } }
解決方式2
并發協作模型“生產者/消費者模式”——>信號燈法
-
舉例:
// 測驗消費者和生產者問題2:信號燈法 public class TextPC2 { public static void main(String[] args) { TV tv = new TV(); new Player(tv).start(); new Watcher(tv).start(); } } // 生產者--> 演員 class Player extends Thread{ TV tv; public Player(TV tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { if (i%2==0){ this.tv.play("快樂大本營播放中"); }else{ this.tv.play("抖音:我就是廣告"); } } } } // 消費者--> 觀眾 class Watcher extends Thread{ TV tv; public Watcher(TV tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { this.tv.watch(); } } } // 產品--> 節目 class TV{ // 演員表演,觀眾等待 T // 觀眾觀看,演員等待 F String voice; // 表演的節目 boolean flag = true; // 表演 public synchronized void play(String voice){ if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演員表演了:"+voice); // 通知觀眾觀看 this.notifyAll();// 通知喚醒 this.voice = voice; // 如果 flag是true 就取反,相同是flase 取 true this.flag = !this.flag; } // 觀看 public synchronized void watch(){ if (flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("觀眾觀看了:"+voice); this.flag = !this.flag; // 通知演員表演 this.notifyAll(); } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/275451.html
標籤:java
上一篇:Qt信號槽原始碼剖析(二)
下一篇:框架的靈魂之注解基礎篇
