Java多線程生產(chǎn)者消費(fèi)者模式實(shí)現(xiàn)過(guò)程解析
單生產(chǎn)者與單消費(fèi)者
示例:
public class ProduceConsume { public static void main(String[] args) { String lock = new String(""); Produce produce = new Produce(lock); Consume consume = new Consume(lock); new Thread(() -> { while (true) { produce.setValue(); } }, "ProductThread").start(); new Thread(() -> { while (true) { consume.getValue(); } }, "ConsumeThread").start(); } /** * 生產(chǎn)者 */ static class Produce { private String lock; public Produce(String lock) { this.lock = lock; } public void setValue() { try { synchronized (lock) { if (!ValueObject.value.equals("")) { lock.wait(); } String value = System.currentTimeMillis() + "_" + System.nanoTime(); System.out.println("set的值是" + value); ValueObject.value = value; lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 消費(fèi)者 */ static class Consume { private String lock; public Consume(String lock) { this.lock = lock; } public void getValue() { try { synchronized (lock) { if (ValueObject.value.equals("")) { lock.wait(); } System.out.println("get的值是" + ValueObject.value); ValueObject.value = ""; lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ValueObject { public static String value = ""; } }
執(zhí)行結(jié)果如下:
多生產(chǎn)者與多消費(fèi)者
這種模式下,容易出現(xiàn)“假死”,也就是全部線程都進(jìn)入了 WAITNG 狀態(tài),程序不在執(zhí)行任何業(yè)務(wù)功能了,整個(gè)項(xiàng)目呈停止?fàn)顟B(tài)。
示例:
public class MultiProduceConsume { public static void main(String[] args) throws InterruptedException { String lock = new String(""); Produce produce = new Produce(lock); Consume consume = new Consume(lock); Thread[] pThread = new Thread[2]; Thread[] cThread = new Thread[2]; for (int i = 0; i < 2; i++) { pThread[i] = new Thread(() -> { while (true) { produce.setValue(); } }, "生產(chǎn)者" + (i + 1)); cThread[i] = new Thread(() -> { while (true) { consume.getValue(); } }, "消費(fèi)者" + (i + 1)); pThread[i].start(); cThread[i].start(); } Thread.sleep(5000); Thread[] threadArray = new Thread[Thread.currentThread().getThreadGroup().activeCount()]; Thread.currentThread().getThreadGroup().enumerate(threadArray); for (int i = 0; i < threadArray.length; i++) { System.out.println(threadArray[i].getName() + " " + threadArray[i].getState()); } } static class Produce { private String lock; public Produce(String lock) { this.lock = lock; } public void setValue() { try { synchronized (lock) { while(!ValueObject.value.equals("")) { System.out.println("生產(chǎn)者 " + Thread.currentThread().getName() + " WAITING了⭐"); lock.wait(); } System.out.println("生產(chǎn)者 " + Thread.currentThread().getName() + " RUNNABLE了"); String value = System.currentTimeMillis() + "_" + System.nanoTime(); ValueObject.value = value; lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class Consume { private String lock; public Consume(String lock) { this.lock = lock; } public void getValue() { try { synchronized (lock) { while (ValueObject.value.equals("")) { System.out.println("消費(fèi)者 " + Thread.currentThread().getName() + " WAITING了⭐"); lock.wait(); } System.out.println("消費(fèi)者 " + Thread.currentThread().getName() + "RUNNABLE了"); ValueObject.value = ""; lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ValueObject { public static String value = ""; } }
運(yùn)行結(jié)果如圖:
分析:
雖然代碼中通過(guò) wait/notify 進(jìn)行通信了,但是不能保證 notify 喚醒的一定是異類(lèi),也可能是同類(lèi),比如“生產(chǎn)者”喚醒了“生產(chǎn)者”這樣的情況。
解決方案:
假死出現(xiàn)的主要原因是有可能連續(xù)喚醒了同類(lèi)。所以解決方案很簡(jiǎn)單,就是把 notify() 改為 notifyAll() 即可。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java?RabbitMQ消息隊(duì)列詳解常見(jiàn)問(wèn)題
- java中RabbitMQ高級(jí)應(yīng)用
- Java實(shí)現(xiàn)Kafka生產(chǎn)者消費(fèi)者代碼實(shí)例
- Java多線程并發(fā)生產(chǎn)者消費(fèi)者設(shè)計(jì)模式實(shí)例解析
- Java多線程 生產(chǎn)者消費(fèi)者模型實(shí)例詳解
- Java多線程 BlockingQueue實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型詳解
- Java編寫(xiě)簡(jiǎn)易rabbitmq生產(chǎn)者與消費(fèi)者的代碼
相關(guān)文章
使用mybatis-plus報(bào)錯(cuò)Invalid bound statement (not found)錯(cuò)誤
這篇文章主要介紹了使用mybatis-plus報(bào)錯(cuò)Invalid bound statement (not found)錯(cuò)誤,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Java 獲取網(wǎng)絡(luò)302重定向URL的方法
在本篇文章里小編給大家整理的是關(guān)于Java 獲取網(wǎng)絡(luò)302重定向URL的方法以及相關(guān)知識(shí)點(diǎn),有興趣的朋友們參考下。2019-08-08nacos配置注冊(cè)中心時(shí)指定命名空間不起作用的問(wèn)題
這篇文章主要介紹了nacos配置注冊(cè)中心時(shí)指定命名空間不起作用的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01java實(shí)現(xiàn)Img與PDF相互轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)Img與PDF相互轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Java8 Optional優(yōu)雅空值判斷的示例代碼
這篇文章主要介紹了Java8 Optional優(yōu)雅空值判斷的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范
今天小編就為大家分享一篇關(guān)于Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12java開(kāi)發(fā)之MD5加密算法的實(shí)現(xiàn)
本篇文章介紹了,java開(kāi)發(fā)之MD5加密算法的實(shí)現(xiàn)。需要的朋友參考下2013-05-05Java實(shí)現(xiàn)簡(jiǎn)易計(jì)算器(逆波蘭表達(dá)式)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)易計(jì)算器,逆波蘭表達(dá)式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07