java中生產(chǎn)者消費者問題和代碼案例
應(yīng)用場景
假設(shè)倉庫中只能存放一件產(chǎn)品,生產(chǎn)者將生產(chǎn)出來的產(chǎn)品放入倉庫,消費者將倉庫中產(chǎn)品取走消費
如果倉庫中沒有產(chǎn)品,則生產(chǎn)者將產(chǎn)品放入倉庫,否則停止生產(chǎn)并等待,直到倉庫中的產(chǎn)品被消費者取走為止
如果倉庫中放有產(chǎn)品,則消費者可以將產(chǎn)品取走消費,否則停止消費并等待,直到倉庫中再次放入產(chǎn)品為止
分析
這是一個線程同步問題,生產(chǎn)者和消費者共享同一個資源,并且生產(chǎn)者和消費者之間相互依賴,互為條件。
對于生產(chǎn)者,沒有生產(chǎn)產(chǎn)品之前,要通知消費者等待,而生產(chǎn)了產(chǎn)品之后,又需要馬上通知消費者消費
對于消費者,在消費之后,要通知生產(chǎn)者已經(jīng)結(jié)束消費,需要生產(chǎn)新的產(chǎn)品以供消費
在生產(chǎn)者消費者問題中,僅有synchronized是不夠的
synchronized可阻止并發(fā)更新同一個共享資源,實現(xiàn)了同步
synchronized不能用來實現(xiàn)不同線程之間的消息傳遞(通信)
Java提供了幾個方法解決線程之間的通信問題
方法名 | 作用 |
---|---|
wait() | 表示線程一直等待,直到其他線程通知,與sleep不同,wait()會釋放鎖 |
wait(long timeout) | 指定等待的毫秒數(shù) |
notify() | 喚醒一個處于等待狀態(tài)的線程 |
notifyAll() | 喚醒同一個對象上所有調(diào)用wait()方法的線程,優(yōu)先級別高的線程優(yōu)先調(diào)度 |
注意:均是Object類的方法,都只能在同步方法或者同步代碼塊中使用,否則會拋出異常
解決方法
管程法
生產(chǎn)者:負責生產(chǎn)數(shù)據(jù)的模塊(可能是方法、對象、線程、進程)
消費者:負責處理數(shù)據(jù)的模塊(可能是方法、對象、線程、進程)
緩沖區(qū):消費者不能直接使用生產(chǎn)者的數(shù)據(jù),他們之間有個“緩沖區(qū)”
生產(chǎn)者將生產(chǎn)好的數(shù)據(jù)放入緩沖區(qū),消費者從緩沖區(qū)拿出數(shù)據(jù)
代碼案例
//使用緩沖區(qū)解決生產(chǎn)者消費者模型 public class TestPC { public static void main(String[] args) { SynContainer container = new SynContainer(); new Producer(container).start(); new Consumer(container).start(); } } ? class Producer extends Thread{ SynContainer synContainer; public Producer(SynContainer synContainer){ this.synContainer = synContainer; } // 生產(chǎn) @Override public void run() { for (int i = 0; i < 100; i++) { synContainer.push(new Chicken(i)); System.out.println("生產(chǎn)了"+i+"只雞"); } } } ? class Consumer extends Thread{ SynContainer synContainer; public Consumer(SynContainer synContainer){ this.synContainer = synContainer; } // 消費 @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消費了-->"+synContainer.pop().id+"只雞"); } } } ? //產(chǎn)品 class Chicken{ int id; public Chicken(int id) { this.id = id; } } ? //緩沖區(qū) class SynContainer{ Chicken[] chickens = new Chicken[10]; int count = 0; //生產(chǎn)者放入產(chǎn)品 public synchronized void push(Chicken chicken){ //如果容器滿了就要等到消費者消費 if (count==chickens.length){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //通知消費者消費,自身進入等待 } //沒有滿的話則生產(chǎn) chickens[count] = chicken; count++; //通知消費者消費 this.notifyAll(); } ? //生產(chǎn)者消費產(chǎn)品 public synchronized Chicken pop(){ if (count==0){ //等待生產(chǎn)者生產(chǎn) try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } count--; Chicken chicken = chickens[count]; //消費了,可以通知生產(chǎn)者繼續(xù)生產(chǎn) this.notifyAll(); return chicken; } }
信號燈法
通過標志位 true 或者 false 來進行判斷
代碼案例
//信號燈法測試生產(chǎn)者消費者模型 即標志位 public class TestPC2 { public static void main(String[] args) { TV tv = new TV(); new Player(tv).start(); new Audiance(tv).start(); } ? } ? //生產(chǎn)者-->演員 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 Audiance extends Thread{ TV tv; public Audiance(TV tv){ this.tv = tv; } ? @Override public void run() { for (int i = 0; i < 20; i++) { tv.watch(); } } } ? //產(chǎn)品-->節(jié)目 class TV{ //演員表演 觀眾等待 T //觀眾觀看 演員等待 F String show;//表演的節(jié)目 boolean flag = true; ? //表演 public synchronized void play(String show){ if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演員表演了:"+show); //通知觀眾 this.notifyAll(); this.show = show; this.flag = !this.flag; } ? //觀看 public synchronized void watch(){ if (flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("觀看了"+show); //通知演員表演 this.notifyAll(); this.flag = !this.flag; } }
總結(jié)
到此這篇關(guān)于java中生產(chǎn)者消費者問題和代碼案例的文章就介紹到這了,更多相關(guān)java生產(chǎn)者消費者問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
談?wù)劄镴AXB和response設(shè)置編碼,解決wechat4j中文亂碼的問題
中文亂碼是每個程序員都會遇到的問題,本篇文章主要介紹了談?wù)劄镴AXB和response設(shè)置編碼,解決wechat4j中文亂碼的問題,具有一定的參考價值,有興趣的可以了解一下。2016-12-12提交gRPC-spring-boot-starter項目bug修復的pr說明
這篇文章主要介紹了這篇文章主要為大家介紹了gRPC-spring-boot-starter項目提交bug修復的pr的原因說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02