[TOC]
聲明
該系列文章只是記錄本人回顧java多線程編程時候記錄的筆記拱燃。文中所用語言并非嚴謹?shù)膶I(yè)術(shù)語(太嚴謹?shù)男g(shù)語其實本人也不會……)碗誉。難免有理解偏差的地方,歡迎指正弄跌。
另外尝苇,大神請繞路糠溜。不喜勿噴。
畢竟好記性不如爛筆頭嘛蜕着,而且許多東西只要不是你經(jīng)常用的最終都會一丟丟一丟丟地給忘記豹芯。
** 初看之下宽闲,阻塞隊列似乎和多線程沒有多大關(guān)系沿腰。但是平時使用阻塞隊列的場景往往是和線程相關(guān)的纽什。所以枫慷,此處將阻塞隊列也歸入java多線程的分類探孝。 **
1 什么是阻塞隊列
說白了找御,阻塞隊列還是一個隊列(FIFO)讨永。至于隊列的概念就不多說了揭糕。
阻塞隊列和普通隊列的區(qū)別就在阻塞
這個詞吏口。
阻塞的意思,可以這么理解:
- 當嘗試隊列出隊操作時舟铜,若隊列已經(jīng)是空的谆刨,則調(diào)用出隊操作的線程將被阻塞血柳,直到隊列有可用元素為止
- 當嘗試隊列入隊操作時难捌,若隊列已經(jīng)是滿的,則調(diào)用入隊操作的線程將被阻塞击敌,直到隊列不再是滿的為止
2 JDK提供的阻塞隊列
2.1 JDK內(nèi)置的阻塞隊列
- ArrayBlockingQueue:
數(shù)組
結(jié)構(gòu)的有界
阻塞隊列 - LinkedBlockingQueue:
鏈表
結(jié)構(gòu)的有界
阻塞隊列 - LinkedTransferQueue:
鏈表
結(jié)構(gòu)的無界
阻塞隊列 - LinkedBlockingDeque:
鏈表
結(jié)構(gòu)的雙向
阻塞隊列 - PriorityBlockingQueue: 支持按
優(yōu)先級
排序的無界
阻塞隊列 - DelayQueue: 使用
優(yōu)先級隊列(PriorityQueue)
實現(xiàn)的阻塞隊列刃宵,優(yōu)先隊列的比較基準值是時間
- SynchronousQueue: 不知道怎么描述這個隊列,因為他并不真正存儲元素牲证。每個插入操作必須等待另一個線程的移除操作十厢,同樣一個移除操作都等待另一個線程的插入操作。
2.2 阻塞隊列不可用時的處理方式
此處要說的是筛武,隊列在特殊情況下的出隊入隊操作的處理榴都。
比如在隊列為空或者隊列已經(jīng)滿了的時候不同的阻塞隊列實現(xiàn)或者不同的方法會有不同的處理方式竿音。
對這種特殊情況的處理柴信,大致有以下一些方法:
- 拋異常
- 隊列為空時進行出隊操作,可能會有
NoSuchElementException
- 隊列已滿時進行入隊操作,可能會有
IllegalStateException
- 隊列為空時進行出隊操作,可能會有
- 返回特殊值
- 拋出
NoSuchElementException
,可以返回null
代替表示隊列為空 - 拋出
IllegalStateException
,可以返回false
表示入隊失敗
- 拋出
- 一直阻塞
- 隊列為空時進行出隊操作,進行出隊操作的線程將被阻塞,直至隊列可用
- 隊列已滿時進行入隊操作,進行入隊操作的線程將被阻塞,直至隊列可用
- 超時退出
- 隊列為空時進行出隊操作,進行出隊操作的線程將被阻塞,直至超時退出(線程也會退出)
- 隊列已滿時進行入隊操作,進行入隊操作的線程將被阻塞,直至超時退出(線程也會退出)
以下圖片是來自《Java并發(fā)編程的藝術(shù)》一書中的總結(jié):
3 使用示例
以上介紹的七種JDK內(nèi)置的阻塞隊列,各有各的使用場景,一篇文章很難介紹清楚序目。
以后會抽空補全各種阻塞隊列的使用場景示例逗旁。
此處英古,就修改一下上篇文章線程通信中那個生產(chǎn)者和消費者的示例程序(http://blog.csdn.net/hylexus/article/details/53446711)。
和上篇文章的不同之處在于艺沼,此處使用阻塞隊列來代替上篇文章中簡單實現(xiàn)的一個數(shù)據(jù)結(jié)構(gòu)棧调鲸。
Container類的實現(xiàn)修改成了下面的樣子:
public static class Container {
private ArrayBlockingQueue<Product> products;
public Container(int size) {
this.products = new ArrayBlockingQueue<>(size);
}
public void put(Product product) {
try {
this.products.put(product);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Product get() {
try {
return this.products.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
完整的代碼示例如下:
import java.util.concurrent.ArrayBlockingQueue;
public class ProducerConsumerByLockingQueue {
public static void main(String[] args) {
Container container = new Container(5);
for (int i = 0; i < 10; i++) {
new Thread(new Producer(container), "P-" + i).start();
new Thread(new Consumer(container), "C-" + i).start();
}
}
public static class Product {
private String name;
public Product(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "[name=" + name + "]";
}
}
public static class Container {
private ArrayBlockingQueue<Product> products;
public Container(int size) {
this.products = new ArrayBlockingQueue<>(size);
}
public void put(Product product) {
try {
this.products.put(product);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Product get() {
try {
return this.products.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
public static class Producer implements Runnable {
private Container container;
public Producer(Container container) {
super();
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Product p = new Product(Thread.currentThread().getName() + "_" + i);
this.container.put(p);
System.out.println("生產(chǎn)者[" + Thread.currentThread().getName() + "]生產(chǎn)>>>>>>:" + p);
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class Consumer implements Runnable {
private Container container;
public Consumer(Container container) {
super();
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Product product = this.container.get();
System.out.println("消費者[" + Thread.currentThread().getName() + "]消費<<<<<<:" + product);
try {
Thread.sleep((long) (Math.random() * 2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
參考資料
- 《java并發(fā)編程的藝術(shù)》