java的知识点34——线程通信 || 生产者与消费者问题
線程通信
應用場景:生產者和消費者問題
? 假設倉庫中只能存放一件產品,生產者將生產出來的產品放入倉庫,消費者將倉庫中產品取走消費
? 如果倉庫中沒有產品,則生產者將產品放入倉庫,否則停止生產并等待,直到倉庫中的產品被消費者取走為止
? 如果倉庫中放有產品,則消費者可以將產品取走消費,否則停止消費并等待,直到倉庫中再次放入產品為止
? ? ? ? ? ? ??
分析
? 這是一個線程同步問題,生產者和消費者共享同一個資源,并且生產者和消費者之間相互依賴,互為條件
? 對于生產者,沒有生產產品之前,要通知消費者等待。而生產了產品之后,又需要馬上通知消費者消費
? 對于消費者,在消費之后,要通知生產者已經消費結束,需要繼續生產新產品以供消費
? 在生產者消費者問題中,僅有synchronized是不夠的
? synchronized可阻止并發更新同一個共享資源,實現了同步
? synchronized不能用來實現不同線程之間的消息傳遞(通信)
Java提供了3個方法解決線程之間的通信問題
線程通信解決方式一:
并發協作模型“生產者/消費者模式” ——》管程法
生產者:?生產者指的是負責生產數據的模塊(這里模塊可能是:方法、對象、線程、進程)
消費者:?消費者指的是負責處理數據的模塊(這里模塊可能是:方法、對象、線程、進程)
緩沖區:?消費者不能直接使用生產者的數據,它們之間有個“緩沖區”。生產者將生產好的數據放入“緩沖區”,消費者從“緩沖區”拿要處理的數據
緩沖區是實現并發的核心,緩沖區的設置有3個好處:
實現線程的并發協作
? ? ??有了緩沖區以后,生產者線程只需要往緩沖區里面放置數據,而不需要管消費者消費的情況;同樣,消費者只需要從緩沖區拿數據處理即可,也不需要管生產者生產的情況。 這樣,就從邏輯上實現了“生產者線程”和“消費者線程”的分離。
解耦了生產者和消費者
? ? ??生產者不需要和消費者直接打交道。
解決忙閑不均,提高效率
? ? ??生產者生產數據慢時,緩沖區仍有數據,不影響消費者消費;消費者處理數據慢時,生產者仍然可以繼續往緩沖區里面放置數據?
協作模型:生產者消費者實現方式一:管程法? ? 借助緩沖區
/*** 協作模型:生產者消費者實現方式一:管程法* 借助緩沖區* @author Administrator**/ public class CoTest01 {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;}@Overridepublic void run() {//生產for(int i=1;i<=20;i++) {System.out.println("生產第--》"+i+"個饅頭");container.push(new Steamedbun(i));}} } //消費者 class Consumer extends Thread{SynContainer container;public Consumer(SynContainer container) {this.container = container;}public void run() {//消費for(int i=1;i<=20;i++) {System.out.println("消費第-->"+container.pop().id+"個饅頭");}} } //緩沖區 class SynContainer{Steamedbun[] buns=new Steamedbun[10]; //存儲容器int count=0; //計數器 // 存儲 生產public synchronized void push(Steamedbun bun) {//何時能生產 容器存在空間//不能生產 只能等待if(count == buns.length) {System.out.println("------"+buns.length+"-----------");try {this.wait(); //線程阻塞 消費者通知生產解除} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }//存在空間 可以生產 // //先指向空的,再放東西進去。 放一個東西,計數加1 這樣做是錯誤的,因為導致count計數不一致 // count++; // buns[count]=bun;buns[count]=bun;count++;//存在數據了,可以通知消費啦this.notifyAll();}//獲取 消費public synchronized Steamedbun pop() {//何時消費 容器中是否存在數據//沒有數據 只有等待if(count==0) {try {this.wait(); //線程阻塞 生產者通知消費解除} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }//存在數據可以消費count--;Steamedbun bun=buns[count];this.notifyAll(); //存在空間了,可以喚醒對方生產了return bun;} } //饅頭 class Steamedbun{int id;public Steamedbun(int id) {this.id=id;} }? ? ? ? ? ? ? ? ??? ?為什么有這種情況????
總結
以上是生活随笔為你收集整理的java的知识点34——线程通信 || 生产者与消费者问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java的知识点33——死锁及解决方案
- 下一篇: java的知识点34——任务定时调度(多