深信服 SANGFOR 裝置密碼恢復和配置備份恢復
阿新 • • 發佈:2020-10-20
執行緒通訊
為什麼要進行執行緒通訊
把一個大的任務放到主執行緒的話,由於順序執行,會嚴重影響程式執行的效率。為了提高效率和併發度,可以將任務解耦為多個執行緒執行,比如一個執行緒接收資料,一個執行緒處理資料,這個時候,執行緒間就會出現互動,也就是執行緒通訊。
生產者消費者模型
執行緒通訊的關鍵應用場景就是生產者消費者問題
- 生產者是負責生產資料的模組,生產產品後,要通知消費者消費
- 消費者是負責處理資料的模組,消費產品後,需要通知生產者生產
- Java提供了幾個用於執行緒通訊的方法
方法名 | 作用 |
---|---|
wait() | 表示執行緒一直等待,直到其他執行緒通知,與sleep不同,會釋放鎖 |
wait(long time out) | 指定等待的毫秒數 |
notify() | 喚醒一個處於等待狀態的執行緒 |
notifiyAll() | 喚醒同一個物件上所有呼叫wait()方法的執行緒,優先級別高的執行緒優先排程 |
生產者消費者的兩種方法實現
管程法:
消費者不能直接使用生產者的資料,需要建立一個緩衝區生產者將生產好的資料放入到緩衝區中,消費者從緩衝區拿出資料。
package MultiProcess; import javax.swing.text.AsyncBoxView; //管程法:利用緩衝區解決 public class TestProduceConsumer { public static void main(String[] args) { SyContaner container = new SyContaner(); new Producetor(container).start(); new Consumer(container).start(); } } //生產者 class Producetor extends Thread{ SyContaner container; public Producetor(SyContaner container){ this.container = container; } //生產 @Override public void run() { for (int i = 0; i < 10; i++) { container.push(new Chicken(i)); System.out.println("生產第" + i + "只雞"); } } } //消費者 class Consumer extends Thread{ SyContaner container; public Consumer(SyContaner container){ this.container = container; } @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("消費第" + container.pop().id + "只雞"); } } } //產品 class Chicken{ int id; public Chicken(int id){ this.id = id; } } class SyContaner{ Chicken[] chickens = new Chicken[10]; int count = 0; //生產者生產產品 public synchronized void push(Chicken chicken){ //滿了,通知消費者消費產品 if(count == chickens.length){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //沒有滿,生產者生產產品 chickens[count] = chicken; count++; this.notifyAll(); } //消費者消費產品 public synchronized Chicken pop(){ //沒有產品了,通知生產者去生產 if(count == 0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //有產品,消費 count--; Chicken chicken = chickens[count]; this.notifyAll(); return chicken; } }
訊號燈法:
消費者可以直接使用生產者生產好的資料,不需要設定緩衝區,
只需要設定一個標誌位,用來控制生產者和消費者的狀態。
package MultiProcess; public class TestProducerConsumer2 { 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++) { tv.watch(); } } } //產品-->節目 class TV{ String voice; boolean flag = true; //true代表需要生產者生產 public synchronized void play(String voice){ if(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演員表演了:" + voice); this.voice = voice; this.flag = !this.flag; //不能繼續表演了,要等別人看完,通知消費者執行緒 this.notifyAll(); } public synchronized void watch(){ if(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("觀看了:" + voice); this.flag = !this.flag; this.notifyAll(); } }