《Java并发编程的艺术》之阻塞队列
阻塞隊(duì)列是一個(gè)支持兩個(gè)附加操作的隊(duì)列。這兩個(gè)附加的操作支持阻塞的插入和移除方法:
1) 支持阻塞的插入方法:當(dāng)隊(duì)列滿時(shí),隊(duì)列會阻塞執(zhí)行插入的線程
2) 支持阻塞的移除方法:當(dāng)隊(duì)列空時(shí),隊(duì)列會阻塞執(zhí)行移除的線程
方法總結(jié):
| 插入方法 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
| 移除方法 | 無 | poll() | take() | poll(time, unit) |
| 檢測方法 | element() | peek() | 無 | 無 |
- 拋出異常:當(dāng)隊(duì)列滿時(shí),插入元素會拋出IllegalStateException;
- 返回特殊值:offer()是入隊(duì)方法,當(dāng)插入成功時(shí)返回true,插入失敗返回false;poll()是出隊(duì)方法,當(dāng)出隊(duì)成功時(shí)返回元素的值,隊(duì)列為空時(shí)返回null
- 一直阻塞:當(dāng)隊(duì)列滿時(shí),阻塞執(zhí)行插入方法的線程;當(dāng)隊(duì)列空時(shí),阻塞執(zhí)行出隊(duì)方法的線程
- 超時(shí)退出:顧名思義
在JDK7里,Java的阻塞隊(duì)列總共有七個(gè),每個(gè)類都繼承AbstractQueue:
- ArrayBlockingQueue
- LinkedTransferQueue
- SynchronousQueue
- DelayQueue
- LinkedBlockingDeque
- LinkedBlockingQueue
- PriorityBlockingQueue
ArrayBlockingQueue
該類是通過數(shù)組實(shí)現(xiàn)的有界阻塞隊(duì)列,此隊(duì)列按照FIFO的原則對元素進(jìn)行排列。默認(rèn)情況下不保證線程公平的訪問隊(duì)列,所謂公平訪問是指阻塞的線程,可以按照阻塞的先后順序訪問隊(duì)列,即先阻塞的先訪問。公平訪問是由ReentrantLock的公平鎖實(shí)現(xiàn)的:
public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)throw new IllegalArgumentException();this.items = new Object[capacity];lock = new ReentrantLock(fair);notEmpty = lock.newCondition();notFull = lock.newCondition(); }LinkedBlockingQueue
該類是一個(gè)用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列(也不算有界,只是因?yàn)橛?jì)數(shù)器最多只能計(jì)Integer.MAX_VALUE)。此隊(duì)列的默認(rèn)和最大長度為Integer.MAX_VALUE。按照先進(jìn)先出的原則對元素進(jìn)行排列。
PriorityBlockingQueue
該類是一個(gè)支持優(yōu)先級的無界阻塞隊(duì)列。默認(rèn)情況下元素采取自然升序的排序方式。也可以自定義類實(shí)現(xiàn)compareTo()來指定元素排序規(guī)則,或者初始化時(shí)指定Comparator來對元素排序。
詳見:坑還沒填,遲點(diǎn)填
DelayQueue
支持延時(shí)獲取元素的無界阻塞隊(duì)列。隊(duì)列使用PriorityQueue來實(shí)現(xiàn),隊(duì)列中的元素必須實(shí)現(xiàn)Delayed接口,再創(chuàng)建元素時(shí)可以指定多久才能從隊(duì)列中獲取當(dāng)前原色,只有在延遲期滿時(shí)才能從隊(duì)列中提取元素。
運(yùn)用場景:
- 緩存系統(tǒng)的設(shè)計(jì):可以用DelayQueue保存緩存元素的有效期,使用一個(gè)線程循環(huán)查詢DelayQueue,一旦能從DelayQueue中獲取元素,表示緩存有效期到了
- 定時(shí)任務(wù)調(diào)度:使用DelayQueue保存當(dāng)天將會執(zhí)行的任務(wù)和執(zhí)行時(shí)間,一旦從DelayQueue中獲取到任務(wù)就開始執(zhí)行,比如TimerQueue
執(zhí)行流程如下所示:
首先實(shí)現(xiàn)Delayed接口:
java @Override public long getDelay(TimeUnit unit){ // 返回當(dāng)前元素還需要等待多久,當(dāng)返回<0的值時(shí),表示可以出隊(duì);>0時(shí),表示仍需要等待 }
第二步,每次offer()時(shí),往PriorityQueue插入元素會自行排序,按照自然升序排序
第三步,每次獲取時(shí)(調(diào)用take(),才能有阻塞的功能),如果時(shí)間未滿會先阻塞
for (;;) {E first = q.peek();if (first == null)available.await();else {long delay = first.getDelay(NANOSECONDS);if (delay <= 0)return q.poll();first = null; // don't retain ref while waitingif (leader != null)available.await();else {Thread thisThread = Thread.currentThread();leader = thisThread;try {available.awaitNanos(delay);} finally {if (leader == thisThread)leader = null;}}} }具體的可以看: 了解之DelayQueue
SynchronousQueue
一個(gè)不存儲元素的隊(duì)列,生產(chǎn)者生產(chǎn)一個(gè),消費(fèi)者消費(fèi)一個(gè),每一個(gè)put操作都需要等待一個(gè)take操作。該隊(duì)列主要負(fù)責(zé)生產(chǎn)者線程處理的數(shù)據(jù)傳遞給消費(fèi)者線程。比較適合傳遞性場景。其吞吐量高于ArrayBlockingQueue和LinkedBlockingQueue
LinkedTransferQueue
該類主要添加了兩個(gè)方法:transfer()和tryTransfer()
transfer() 主要是當(dāng)消費(fèi)者線程在等待的時(shí)候,生產(chǎn)者一產(chǎn)生元素,就立刻交給消費(fèi)者,不需要再進(jìn)行額外的入隊(duì)操作;如果沒有消費(fèi)者在等待,就先進(jìn)入隊(duì)尾。
tryTransfer() 用來試探生產(chǎn)者傳入的元素是否能直接傳給消費(fèi)者。
具體的可以看:了解之LinkedTansferQueue
總結(jié)
- ArrayBlockingQueue
- LinkedBlockingQueue
- LinkedBlockingDeque
- SynchronousQueue
上面四個(gè)是較為簡單的,數(shù)據(jù)結(jié)構(gòu)和各個(gè)方法都較為簡單就不一一闡述了。剩下三個(gè)則是比較大頭的,而且比較新穎,打算單獨(dú)拎出來講解
該章主要是粗略的了解一下其他阻塞隊(duì)列的功能,對于一些不常見的類,后續(xù)會補(bǔ)上詳細(xì)的分析(其實(shí)是先補(bǔ)充一波數(shù)據(jù)結(jié)構(gòu)和算法)
轉(zhuǎn)載于:https://www.cnblogs.com/codeleven/p/10963265.html
總結(jié)
以上是生活随笔為你收集整理的《Java并发编程的艺术》之阻塞队列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python字符串去头尾_带你认识优秀的
- 下一篇: 固态硬盘故障检测_diskgenius检