Java線程通信中關(guān)于生產(chǎn)者與消費(fèi)者案例分析
相關(guān)方法:
wait():一旦執(zhí)行此方法,當(dāng)前線程就進(jìn)入阻塞狀態(tài),并釋放同步監(jiān)視器。
notify():一旦執(zhí)行此方法,就會(huì)喚醒被wait的一個(gè)線程,如果有多個(gè)線程被wait,就喚醒優(yōu)先級(jí)高的那個(gè)。
notifyAll():一旦執(zhí)行此方法,就會(huì)喚醒所有被wait的線程。
說(shuō)明:
1.wait(),notify(),notifyAll()三個(gè)方法必須使用在同步代碼塊或同步方法中。
2.wait(),notify(),notifyAll()三個(gè)方法的調(diào)用者必須是同步代碼塊或同步方法中的同步監(jiān)視器。
否則,會(huì)出現(xiàn)IllegalMonitorStateException異常
3.wait(),notify(),notifyAll()三個(gè)方法是定義在java.lang.Object類中。
線程通信的例子:使用兩個(gè)線程打印1-100.線程1,線程2 交替打印
class Number implements Runnable{ private int number = 1; @Override public void run() { while(true){ synchronized (this) { notify(); if(number <= 100){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + number); number++; try { //使得調(diào)用如下wait()方法的線程進(jìn)入阻塞狀態(tài) wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else{ break; } } } } } public class CommunicationTest { public static void main(String[] args) { Number number = new Number(); Thread t1 = new Thread(number); Thread t2 = new Thread(number); t1.setName("線程1"); t2.setName("線程2"); t1.start(); t2.start(); } }
經(jīng)典例題:生產(chǎn)者/消費(fèi)者問(wèn)題
生產(chǎn)者(Productor)將產(chǎn)品交給店員(Clerk),而消費(fèi)者(Customer)從店員處取走產(chǎn)品店員一次只能持有固定數(shù)量的產(chǎn)品(比如:20),如果生產(chǎn)者試圖生產(chǎn)更多的產(chǎn)品,店員會(huì)叫生產(chǎn)者停一下,如果店中有空位放產(chǎn)品了再通知生產(chǎn)者繼續(xù)生產(chǎn),如果店中沒(méi)有產(chǎn)品了,店員會(huì)告訴消費(fèi)者等一下,如果店中有產(chǎn)品了再通知消費(fèi)者來(lái)取走產(chǎn)品。
這里可能出現(xiàn)兩個(gè)問(wèn)題:
>生產(chǎn)者比消費(fèi)者快時(shí),消費(fèi)者會(huì)漏掉一些數(shù)據(jù)沒(méi)有取到。
>消費(fèi)者比生產(chǎn)者塊時(shí),消費(fèi)者會(huì)取相同的數(shù)據(jù)。
分析:
- 是否是多線程問(wèn)題?是,生產(chǎn)者線程,消費(fèi)者線程
- 是否有共享數(shù)據(jù)?有,店員(或產(chǎn)品)
- 如何解決線程安全問(wèn)題?同步機(jī)制,有三種方法
- 是否涉及線程的通信?是
class Clerk{ private int productCount = 0; //生產(chǎn)產(chǎn)品 public synchronized void produceProduct() { if(productCount < 20){ productCount++; System.out.println(Thread.currentThread().getName() + ":開始生產(chǎn)第" + productCount + "個(gè)產(chǎn)品"); notify(); }else{ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } //消費(fèi)產(chǎn)品 public synchronized void consumeProduct() { if(productCount > 0){ System.out.println(Thread.currentThread().getName() + ":開始消費(fèi)第" + productCount + "個(gè)產(chǎn)品"); productCount--; notify(); }else{ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Producer extends Thread{//生產(chǎn)者 private Clerk clerk; public Producer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { System.out.println(getName() + ":開始生產(chǎn)產(chǎn)品....."); while(true){ try { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); } } } class Consumer extends Thread{//消費(fèi)者 private Clerk clerk; public Consumer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { System.out.println(getName() + ":開始消費(fèi)產(chǎn)品....."); while(true){ try { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consumeProduct(); } } } public class ProductTest { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); p1.setName("生產(chǎn)者1"); Consumer c1 = new Consumer(clerk); c1.setName("消費(fèi)者1"); Consumer c2 = new Consumer(clerk); c2.setName("消費(fèi)者2"); p1.start(); c1.start(); c2.start(); } }
sleep()和wait()的異同?
1.相同點(diǎn):一旦執(zhí)行方法,都可以使得當(dāng)前的線程進(jìn)入阻塞狀態(tài)。
2.不同點(diǎn):
1)兩個(gè)方法聲明的位置不同,Thread類中聲明sleep(),Object類中聲明wait()
2)調(diào)用的要求不同:sleep()可以在任何需要的場(chǎng)景下調(diào)用。wait()必須使用在同步代碼塊或同步方 法中
3)關(guān)于是否釋放同步監(jiān)視器:如果兩個(gè)方法都使用在同步代碼塊或同步方法中,sleep()不會(huì)釋放 鎖,wait()會(huì)釋放鎖
到此這篇關(guān)于Java線程通信中關(guān)于生產(chǎn)者與消費(fèi)者案例分析的文章就介紹到這了,更多相關(guān)Java線程通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot后端接收前端傳數(shù)組參數(shù)三種方法
這篇文章主要給大家介紹了關(guān)于springboot后端接收前端傳數(shù)組參數(shù)三種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-07-07Java讀取項(xiàng)目json文件并轉(zhuǎn)為JSON對(duì)象的操作
這篇文章主要介紹了Java讀取項(xiàng)目json文件并轉(zhuǎn)為JSON對(duì)象的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java數(shù)據(jù)結(jié)構(gòu)與算法之棧(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之棧,棧是先進(jìn)后出的數(shù)據(jù)的結(jié)構(gòu),本文通過(guò)文字說(shuō)明與實(shí)例代碼相結(jié)合的形式給大家介紹的非常詳細(xì),需要的朋友跟著小編一起學(xué)習(xí)吧2017-04-04Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)賦值的方法
這篇文章主要介紹了Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)賦值的方法,涉及到通用字段自動(dòng)填充的最佳實(shí)踐總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07springboot與mybatis整合實(shí)例詳解(完美融合)
大家都知道springboot搭建一個(gè)spring框架只需要秒秒鐘。下面通過(guò)實(shí)例代碼給大家介紹一下springboot與mybatis的完美融合,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-09-09spring boot整合mybatis+mybatis-plus的示例代碼
這篇文章主要介紹了spring boot整合mybatis+mybatis-plus的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01