[19/04/11-星期四] 多线程_并发协作(生产者/消费者模式_2种解决方案(管程法和信号灯法))...
一、概念
多線程環境下,我們經常需要多個線程的并發和協作。這個時候,就需要了解一個重要的多線程并發協作模型“生產者/消費者模式”。
? 什么是生產者?
? ? ??生產者指的是負責生產數據的模塊(這里模塊可能是:方法、對象、線程、進程)。
? 什么是消費者?
? ? ??消費者指的是負責處理數據的模塊(這里模塊可能是:方法、對象、線程、進程)。
? 什么是緩沖區?
? ? ??消費者不能直接使用生產者的數據,它們之間有個“緩沖區”。生產者將生產好的數據放入“緩沖區”,消費者從“緩沖區”拿要處理的數據。
? ? ??緩沖區是實現并發的核心,緩沖區的設置有3個好處:
? 實現線程的并發協作
? ? ??有了緩沖區以后,生產者線程只需要往緩沖區里面放置數據,而不需要管消費者消費的情況;同樣,消費者只需要從緩沖區拿數據處理即可,
也不需要管生產者生產的情況。 這樣,就從邏輯上實現了“生產者線程”和“消費者線程”的分離。
? 解耦了生產者和消費者
? ? ??生產者不需要和消費者直接打交道。
? 解決忙閑不均,提高效率
? ? ??生產者生產數據慢時,緩沖區仍有數據,不影響消費者消費;消費者處理數據慢時,生產者仍然可以繼續往緩沖區里面放置數據 。
線程并發協作總結:
? ? ? 線程并發協作(也叫線程通信),通常用于生產者/消費者模式,情景如下:
? ? ??1. 生產者和消費者共享同一個資源,并且生產者和消費者之間相互依賴,互為條件。
? ? ??2. 對于生產者,沒有生產產品之前,消費者要進入等待狀態。而生產了產品之后,又需要馬上通知消費者消費。
? ? ??3. 對于消費者,在消費之后,要通知生產者已經消費結束,需要繼續生產新產品以供消費。
? ? ??4. 在生產者消費者問題中,僅有synchronized是不夠的。
? ? ? ??· synchronized可阻止并發更新同一個共享資源,實現了同步;
? ? ? ??· synchronized不能用來實現不同線程之間的消息傳遞(通信)。
? ? ??5. 那線程是通過哪些方法來進行消息傳遞(通信)的呢?見如下總結:
? ? ??6. 以上方法均是java.lang.Object類的方法;
? ? ??都只能在同步方法或者同步代碼塊中使用,否則會拋出異常。
【管程法】
/*** 生產者消費者模型實現方式一:管程法* 4個角色: 生產者、消費者、緩沖區、生產的商品* */ package cn.sxt.thread;public class Test_0411_Produce {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) {super();this.container = container;}//開始生產,生產50個public void run() { for (int i = 0; i < 50; i++) {System.out.println("生產-->第"+i+"個包子");container.push(new Goods(i));}} } //消費者 class Consumer extends Thread{SynContainer container;public Consumer(SynContainer container) {super();this.container = container;}//開始消費,消費100個會等待public void run() { for (int i = 0; i < 100; i++) {System.out.println("消費---->第"+container.pop().id+"個包子");}} }//緩沖區 class SynContainer {Goods[] goods=new Goods[10];int count;//存public synchronized void push(Goods good1) {//緩沖區有空格就生產if (count==goods.length) {//此種情況下表示緩沖區滿了,不能生產try {this.wait();//線程阻塞。生產通知消費,解除阻塞} catch (InterruptedException e) {//消費者通知生產,就解除 }}goods[count]=good1;count++;this.notifyAll();//存在數據了,可以喚醒消費者消費了 }//取public synchronized Goods pop() {//存在數據就拿,沒有數據就等待if (count==0) {try {this.wait();//線程阻塞。生產通知消費,解除阻塞} catch (InterruptedException e) {}}count--;//從最后一個位置拿Goods good2=goods[count];this.notifyAll();//存在空間可喚醒對方生產了return good2;} } //商品 class Goods {int id;public Goods(int id) {super();this.id = id;}}?
【信號燈法】
/*** 生產者消費者模型實現方式二:信號燈法,借助標志位* 3要素:生產者(演員)、消費者(觀眾)、統一資源(電視劇)* */ package cn.sxt.thread;public class Test_0411_Signal {public static void main(String[] args) {Tv tv=new Tv();new Actor(tv).start();new Watcher(tv).start(); } }class Actor extends Thread{Tv tv;public Actor(Tv tv) {this.tv = tv;}public void run() {for (int i = 0; i < 10; 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;}public void run() {for (int i = 0; i < 10; i++) {tv.watch(); }} }class Tv{String vioce;boolean flag=true;//信號燈 真:表示演員表演,觀眾等待 假:觀眾觀看,演員等待public synchronized void play(String v) {//演員等待if (!flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();} }System.out.println("表演了:"+v);this.vioce=v;this.notifyAll();//喚醒 this.flag=!this.flag;//切換標志 }public synchronized void watch() {//觀眾等待if (flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();} }System.out.println("聽到了:"+vioce);this.notifyAll();//喚醒this.flag=!this.flag;}}?
轉載于:https://www.cnblogs.com/ID-qingxin/p/10679974.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的[19/04/11-星期四] 多线程_并发协作(生产者/消费者模式_2种解决方案(管程法和信号灯法))...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringSecurityOAuth使
- 下一篇: Egret的容器--删除对象,遮罩