Java使用阻塞隊(duì)列BlockingQueue實(shí)現(xiàn)生產(chǎn)者消費(fèi)者的方法
什么是阻塞隊(duì)列
阻塞隊(duì)列(BlockingQueue)是一個(gè)支持兩個(gè)附加操作的隊(duì)列。這兩個(gè)附加的操作支持阻塞的插入和移除方法。
- 1、支持阻塞的插入方法:意思是當(dāng)隊(duì)列滿時(shí),隊(duì)列會(huì)阻塞插入元素的線程,直到隊(duì)列不滿。
- 2、支持阻塞的移除方法:意思是在隊(duì)列為空時(shí),獲取元素的線程會(huì)等待隊(duì)列變?yōu)榉强铡?/li>
阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場景,生產(chǎn)者是向隊(duì)列里添加元素的線程,消費(fèi)者是從隊(duì)列里取元素的線程。 阻塞隊(duì)列就是生產(chǎn)者用來存放元素、消費(fèi)者用來獲取元素的容器。
Java中提供了幾個(gè)對(duì)BlockingQueue的實(shí)現(xiàn)類,如: ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue 等
在處理生產(chǎn)者/消費(fèi)者問題上 我們將會(huì)使用ArrayBlockingQueue來實(shí)現(xiàn),如下是我們需知道的重要方法:
- put(E e): 這個(gè)方法用于向隊(duì)列中插入元素,如果隊(duì)列已滿,需要等待可用的這間。
- E take(): 這個(gè)方法用于從隊(duì)列頭部獲取或者移除元素,如果隊(duì)列為空則需要等待可用的元素。
使用BlockingQueue來解決生產(chǎn)者/消費(fèi)者 示例
Mantou類
Producer產(chǎn)生的普通Java對(duì)象,并添加到隊(duì)列中。
/**
* Producer產(chǎn)生的饅頭類
* @author itmyhome
*
*/
public class Mantou {
private String mantou;
public Mantou(String mantou) {
this.mantou = mantou;
}
public String getMantou() {
return mantou;
}
public void setMantou(String mantou) {
this.mantou = mantou;
}
}Producer生產(chǎn)者類
Producer這個(gè)類會(huì)產(chǎn)生消息并將其放入隊(duì)列中。
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
BlockingQueue<Mantou> queue;
public Producer(BlockingQueue<Mantou> queue) {
this.queue = queue;
}
@Override
public void run() {
// 生產(chǎn)饅頭
for (int i = 0; i < 100; i++) {
Mantou mt = new Mantou("" + i);
try {
Thread.sleep(100);
queue.put(mt);
System.out.println("生產(chǎn)饅頭: " + mt.getMantou());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 添加退出消息
Mantou msg = new Mantou("exit");
try {
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}Consumer消費(fèi)者類
Consumer類會(huì)從隊(duì)列獲取消息進(jìn)行處理。如果獲取的是退出消息則結(jié)束。
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable {
BlockingQueue<Mantou> queue;
public Consumer(BlockingQueue<Mantou> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
Mantou mantou;
// 獲取并處理消息直到接收到“exit”消息
while (!(mantou = queue.take()).getMantou().equals("exit")) {
Thread.sleep(100);
System.out.println("消費(fèi)饅頭: " + mantou.getMantou());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}ProducerConsumerService
生產(chǎn)者/消費(fèi)者的服務(wù)類將會(huì)產(chǎn)生固定大小的BlockingQueue,生產(chǎn)者和消費(fèi)者同時(shí)共享該BlockingQueue,該服務(wù)類會(huì)起啟動(dòng)生產(chǎn)者和消費(fèi)者線程。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @author itmyhome
*
*/
public class ProducerConsumerService {
public static void main(String[] args) {
// 創(chuàng)建大小為10的 BlockingQueue
BlockingQueue<Mantou> queue = new ArrayBlockingQueue<Mantou>(10);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
// 開啟 producer線程向隊(duì)列中生產(chǎn)消息
new Thread(producer).start();
//開啟 consumer線程 中隊(duì)列中消費(fèi)消息
new Thread(consumer).start();
System.out.println("Producer and Consumer has been started");
}
}程序運(yùn)行結(jié)果:
Producer and Consumer has been started
生產(chǎn)饅頭: 0
生產(chǎn)饅頭: 1
消費(fèi)饅頭: 0
消費(fèi)饅頭: 1
生產(chǎn)饅頭: 2
消費(fèi)饅頭: 2
生產(chǎn)饅頭: 3
消費(fèi)饅頭: 3
生產(chǎn)饅頭: 4
消費(fèi)饅頭: 4
生產(chǎn)饅頭: 5
消費(fèi)饅頭: 5
生產(chǎn)饅頭: 6
消費(fèi)饅頭: 6
......
參考資料
[1]: Java并發(fā)編程的藝術(shù)[2]: http://www.cnblogs.com/tonyspark/p/3722013.html
到此這篇關(guān)于Java使用阻塞隊(duì)列BlockingQueue實(shí)現(xiàn)生產(chǎn)者消費(fèi)者的文章就介紹到這了,更多相關(guān)Java生產(chǎn)者消費(fèi)者內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MybatisPlus中@EnumValue注解使用及應(yīng)用場景
@EnumValue注解標(biāo)記在枚舉類型的字段上,表示該字段是枚舉值在數(shù)據(jù)庫中存儲(chǔ)的實(shí)際值,這對(duì)于枚舉的持久化是關(guān)鍵,確保枚舉在數(shù)據(jù)庫中的表示與Java枚舉類的一致性,下面就來詳細(xì)的介紹一下@EnumValue注解如何使用,感興趣的可以了解一下2025-10-10
一篇文章帶你入門Springboot整合微信登錄與微信支付(附源碼)
微信支付是騰訊公司的支付業(yè)務(wù)品牌,微信支付商戶平臺(tái)支持線下場所、公眾號(hào)、小程序、PC網(wǎng)站、APP、企業(yè)微信等經(jīng)營場景快速接入微信支付。這里一篇文章帶你入門!2021-06-06
Springboot非分布式定時(shí)任務(wù)實(shí)現(xiàn)代碼
這篇文章主要介紹了Springboot非分布式定時(shí)任務(wù)實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
springboot掃碼登錄的簡單實(shí)現(xiàn)
本文主要介紹基于SpringBoot + Vue + Android實(shí)現(xiàn)的掃碼登錄,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
SpringBoot整合ShedLock解決定時(shí)任務(wù)防止重復(fù)執(zhí)行的問題
ShedLock是一個(gè)用于分布式系統(tǒng)中防止定時(shí)任務(wù)重復(fù)執(zhí)行的庫,本文主要介紹了SpringBoot整合ShedLock解決定時(shí)任務(wù)防止重復(fù)執(zhí)行的問題,具有一定的參考價(jià)值,感興趣的可以了解一下2025-01-01
現(xiàn)代高效的java構(gòu)建工具gradle的快速入門
和Maven一樣,Gradle只是提供了構(gòu)建項(xiàng)目的一個(gè)框架,真正起作用的是Plugin,本文主要介紹了gradle入門,文中通過示例代碼介紹的非常詳細(xì),感興趣的小伙伴們可以參考一下2021-11-11
idea打不開雙擊IDEA圖標(biāo)沒反應(yīng)的快速解決方案
這篇文章主要介紹了idea打不開雙擊IDEA圖標(biāo)沒反應(yīng)的快速解決方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
MyBatis使用Zookeeper保存數(shù)據(jù)庫的配置可動(dòng)態(tài)刷新的實(shí)現(xiàn)代碼
這篇文章主要介紹了MyBatis使用Zookeeper保存數(shù)據(jù)庫的配置,可動(dòng)態(tài)刷新,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08

