
點(diǎn)贊再看,養(yǎng)成習(xí)慣,公眾號(hào)搜一搜【一角錢技術(shù)】關(guān)注更多原創(chuàng)技術(shù)文章。本文 GitHub org_hejianhui/JavaStudy 已收錄,有我的系列文章。
前言

LinkedBlockingDeque 一個(gè)由于鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列,隊(duì)列頭部和尾部都可以添加和移除元素,多線程并發(fā)時(shí),可以將鎖的競(jìng)爭(zhēng)對(duì)多降到一半。
隊(duì)列創(chuàng)建
BlockingDeque<String> deque = new LinkedBlockingDeque<String>();
應(yīng)用場(chǎng)景
一般多用于生產(chǎn)者消費(fèi)者模式。
我們來(lái)看一個(gè)例子:使用了LinkedBlockingQueue來(lái)模仿生產(chǎn)者線程和消費(fèi)者線程進(jìn)行數(shù)據(jù)生產(chǎn)和消費(fèi)。
package com.niuh.deque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
/**
* <p>
* LinkedBlockingQueue示例,生產(chǎn)者消費(fèi)者
* </p>
*/
public class LinkedBlockingQueueRunner {
public static void main(String[] args) {
BlockingQueue<Integer> shareQueue = new LinkedBlockingDeque<>();
Producer P = new Producer(shareQueue);
Consumer C = new Consumer(shareQueue);
P.start();
C.start();
}
}
/**
* 生產(chǎn)者
*/
class Producer extends Thread {
private BlockingQueue<Integer> sharedQueue;
public Producer(BlockingQueue<Integer> shareQueue) {
super("PRODUCER");
this.sharedQueue = shareQueue;
}
public void run() {
//no synchronization needed
for (int i = 0; i < 10; i++) {
try {
System.out.println(getName() + " produced " + i);
sharedQueue.put(i);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消費(fèi)者
*/
class Consumer extends Thread {
private BlockingQueue<Integer> shareQueue;
public Consumer(BlockingQueue<Integer> shareQueue) {
super("CONSUMER");
this.shareQueue = shareQueue;
}
public void run() {
try {
while (true) {
Integer item = shareQueue.take();
System.out.println(getName() + " consumed " + item);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
工作原理
LinkedBlockingDeque的數(shù)據(jù)結(jié)構(gòu),如下圖所示:

說(shuō)明:
- LinkedBlockingDeque繼承于AbstractQueue,它本質(zhì)上是一個(gè)支持FIFO和FILO的雙向的隊(duì)列。
- LinkedBlockingDeque實(shí)現(xiàn)了BlockingDeque接口,它支持多線程并發(fā)。當(dāng)多線程競(jìng)爭(zhēng)同一個(gè)資源時(shí),某線程獲取到該資源之后,其它線程需要阻塞等待。
- LinkedBlockingDeque是通過(guò)雙向鏈表實(shí)現(xiàn)的。
- first是雙向鏈表的表頭。
- last是雙向鏈表的表尾。
- count是LinkedBlockingDeque的實(shí)際大小,即雙向鏈表中當(dāng)前節(jié)點(diǎn)個(gè)數(shù)。
- capacity是LinkedBlockingDeque的容量,它是在創(chuàng)建LinkedBlockingDeque時(shí)指定的。
- lock是控制對(duì)LinkedBlockingDeque的互斥鎖,當(dāng)多個(gè)線程競(jìng)爭(zhēng)同時(shí)訪問(wèn)LinkedBlockingDeque時(shí),某線程獲取到了互斥鎖lock,其它線程則需要阻塞等待,直到該線程釋放lock,其它線程才有機(jī)會(huì)獲取lock從而獲取cpu執(zhí)行權(quán)。
- notEmpty和notFull分別是“非空條件”和“未滿條件”。通過(guò)它們能夠更加細(xì)膩進(jìn)行并發(fā)控制。
-- 若某線程(線程A)要取出數(shù)據(jù)時(shí),隊(duì)列正好為空,則該線程會(huì)執(zhí)行notEmpty.await()進(jìn)行等待;當(dāng)其它某個(gè)線程(線程B)向隊(duì)列中插入了數(shù)據(jù)之后,會(huì)調(diào)用notEmpty.signal()喚醒“notEmpty上的等待線程”。此時(shí),線程A會(huì)被喚醒從而得以繼續(xù)運(yùn)行。 此外,線程A在執(zhí)行取操作前,會(huì)獲取takeLock,在取操作執(zhí)行完畢再釋放takeLock。
-- 若某線程(線程H)要插入數(shù)據(jù)時(shí),隊(duì)列已滿,則該線程會(huì)它執(zhí)行notFull.await()進(jìn)行等待;當(dāng)其它某個(gè)線程(線程I)取出數(shù)據(jù)之后,會(huì)調(diào)用notFull.signal()喚醒“notFull上的等待線程”。此時(shí),線程H就會(huì)被喚醒從而得以繼續(xù)運(yùn)行。 此外,線程H在執(zhí)行插入操作前,會(huì)獲取putLock,在插入操作執(zhí)行完畢才釋放putLock。
源碼分析
定義
LinkedBlockingDeque的類繼承關(guān)系如下:

其包含的方法定義如下:

BlockingDeque接口
BlockingDeque 繼承 BlockingQueue 和 Deque 兩個(gè)接口,其類繼承關(guān)系圖如下:

其主要的方法如下:

| 接口名 | 說(shuō)明 |
|---|---|
| void addFirst(E e) | 添加元素到頭部。如果沒(méi)有多余的空間。則扔出異常。 |
| void addLast(E e) | 添加元素到尾部。如果沒(méi)有多余的空間。則拋出異常。 |
| boolean offerFirst(E e) | 添加元素到頭部。如果沒(méi)有多余的空間。則返回false |
| boolean offerLast(E e) | 添加元素到尾部。如果沒(méi)有多余的空間。則返回false |
| void putFirst(E e) | 添加元素到頭部。如果沒(méi)有多余的空間。則進(jìn)行等待 |
| void putLast(E e) | 添加元素到尾部。如果沒(méi)有多余的空間。則進(jìn)行等待 |
| boolean offerFirst(E e, long timeout, TimeUnit unit) | 添加元素到頭部。如果沒(méi)有多余的空間。則進(jìn)行等待。具有超時(shí)機(jī)制 |
| boolean offerLast(E e, long timeout, TimeUnit unit) | 添加元素到尾部。如果沒(méi)有多余的空間。則進(jìn)行等待。具有超時(shí)機(jī)制 |
| E takeFirst() | 查詢并移除頭部元素。如果沒(méi)有多余的空間。則進(jìn)行等待。 |
| E takeLast() | 查詢并移除尾部元素。如果沒(méi)有多余的空間。則進(jìn)行等待。 |
成員屬性
從下面可以得到LinkedBlockingDeque內(nèi)部只有一把鎖以及該鎖上關(guān)聯(lián)的兩個(gè)條件,所以可以推斷同一時(shí)刻只有一個(gè)線程可以在隊(duì)頭或者隊(duì)尾執(zhí)行入隊(duì)或出隊(duì)操作??梢园l(fā)現(xiàn)這點(diǎn)和LinkedBlockingQueue不同,LinkedBlockingQueue可以同時(shí)有兩個(gè)線程在兩端執(zhí)行操作。
// 隊(duì)列的頭節(jié)點(diǎn)
transient Node<E> first;
// 隊(duì)列的尾節(jié)點(diǎn)
transient Node<E> last;
// 隊(duì)列中的元素個(gè)數(shù)
private transient int count;
// 隊(duì)列的指定容量
private final int capacity;
// 可重入鎖,保證所有數(shù)據(jù)訪問(wèn)的線程安全
final ReentrantLock lock = new ReentrantLock();
// 出隊(duì)時(shí)的“非空”條件
private final Condition notEmpty = lock.newCondition();
// 入隊(duì)時(shí)的“未滿”條件
private final Condition notFull = lock.newCondition();
內(nèi)部類Node
一個(gè)Node對(duì)象代表一個(gè)鏈表節(jié)點(diǎn),其屬性item表示當(dāng)前節(jié)點(diǎn)保存的元素(item為null時(shí)表示當(dāng)前節(jié)點(diǎn)已經(jīng)被刪除),next屬性表示當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn),prev屬性表示當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)。
static final class Node<E> {
// 節(jié)點(diǎn)數(shù)據(jù)
E item;
// 上一個(gè)節(jié)點(diǎn)
Node<E> prev;
// 下一個(gè)節(jié)點(diǎn)
Node<E> next;
Node(E x) {
item = x;
}
}
構(gòu)造函數(shù)
提供了三個(gè)構(gòu)造方法,LinkedBlockingDeque(int)是其主要的構(gòu)造方法,構(gòu)造方法主要涉及對(duì)隊(duì)列容量的初始化。在使用無(wú)參構(gòu)造方法時(shí),阻塞隊(duì)列的容量是Integer.MAX_VALUE,即無(wú)限大。
在初始化后,隊(duì)列中不含任何元素時(shí),頭節(jié)點(diǎn) 、尾節(jié)點(diǎn)均是null。看到這三個(gè)構(gòu)造方法的結(jié)構(gòu)和LinkedBlockingQueue是相同的。 但是LinkedBlockingQueue是存在一個(gè)哨兵節(jié)點(diǎn)維持頭節(jié)點(diǎn)的,而LinkedBlockingDeque中是沒(méi)有的。
public LinkedBlockingDeque() {
this(Integer.MAX_VALUE);
}
//指定容量
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
}
//將某集合元素放入阻塞隊(duì)列中
public LinkedBlockingDeque(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock lock = this.lock;
lock.lock(); // Never contended, but necessary for visibility
try {
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (!linkLast(new Node<E>(e)))
throw new IllegalStateException("Deque full");
}
} finally {
lock.unlock();
}
}
添加元素
在隊(duì)尾添加元素
put offer add offer 等方法都是在隊(duì)列的尾部添加元素。它們將核心實(shí)現(xiàn)委托給 putLast 、offerLast 、add``Last實(shí)現(xiàn)
public void put(E e) throws InterruptedException {
putLast(e);
}
public boolean offer(E e) {
return offerLast(e);
}
public boolean add(E e) {
addLast(e);
return true;
}
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
return offerLast(e, timeout, unit);
}
putLast(E e)
putLast 在隊(duì)尾添加元素
putLast先獲取lock鎖(lock.lock()),然后嘗試在隊(duì)尾添加一個(gè)新節(jié)點(diǎn)(linkLast(node)),若鏈接新節(jié)點(diǎn)失敗,則(notFull.await())休眠等待直到等到”未滿“通知。
public void putLast(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
while (!linkLast(node))
notFull.await();//休眠等待
} finally {
lock.unlock();
}
}
linkLast 嘗試在隊(duì)列的尾部添加一個(gè)新節(jié)點(diǎn)。主要邏輯:
- 若隊(duì)列已滿,直接返回false(不能鏈接新節(jié)點(diǎn)) ;
- 將待入隊(duì)節(jié)點(diǎn)node作為新的尾節(jié)點(diǎn)添加在隊(duì)尾(
last = node)并更新相關(guān)鏈接關(guān)系; - 元素計(jì)數(shù)加1(
++count); - 喚醒一個(gè)等待"非空"條件的線程(
notEmpty.signal()),最后返回true.
private boolean linkLast(Node<E> node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)//隊(duì)列已滿,不能鏈接新節(jié)點(diǎn)
return false;
Node<E> l = last;
node.prev = l;//設(shè)置node的前驅(qū)節(jié)點(diǎn),它的前驅(qū)為原尾節(jié)點(diǎn)
last = node;//新尾節(jié)點(diǎn)是剛添加的節(jié)點(diǎn)node
//更新原尾節(jié)點(diǎn)l的后繼節(jié)點(diǎn)
if (first == null) //隊(duì)列中沒(méi)有任何節(jié)點(diǎn),last first均未初始化,
//隊(duì)列中只有一個(gè)節(jié)點(diǎn)(元素)時(shí),頭節(jié)點(diǎn)first 和尾節(jié)點(diǎn)last指定同一節(jié)點(diǎn)node
first = node;
else
l.next = node;//原尾節(jié)點(diǎn)l的后繼節(jié)點(diǎn)是新尾節(jié)點(diǎn)(剛添加的節(jié)點(diǎn)node)
++count;//元素個(gè)數(shù)加1
notEmpty.signal();//通知一個(gè)等待"非空"條件的線程
return true;
}
offerLast(E e)
offerLast方法與putLast類似,offerLast在檢測(cè)到隊(duì)列已滿時(shí)會(huì)直接返回false,不會(huì)阻塞等待。
public boolean offerLast(E e) {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
return linkLast(node);
} finally {
lock.unlock();
}
}
offerLast(e, timeout, unit)
多參數(shù)的offerLast方法,它可以看作putLast的超時(shí)版本。
public boolean offerLast(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (!linkLast(node)) {
if (nanos <= 0)//在超時(shí)之后沒(méi)能入隊(duì),返回false
return false;
nanos = notFull.awaitNanos(nanos);//超時(shí)等待
}
return true;
} finally {
lock.unlock();
}
}
addLast(E e)
addLast 在隊(duì)尾添加元素,若隊(duì)列已滿拋出異常。
public void addLast(E e) {
if (!offerLast(e))
throw new IllegalStateException("Deque full");
}
在隊(duì)首添加元素
push(E e)
push 在隊(duì)列的頭部插入元素,調(diào)用addFirst
public void push(E e) {
addFirst(e);
}
addFirst(E e)
在隊(duì)列的頭部插入元素,若隊(duì)列已經(jīng)滿拋出IllegalStateException異常
public void addFirst(E e) {
if (!offerFirst(e))
throw new IllegalStateException("Deque full");
}
putFirst(E e)
putLast在隊(duì)列頭部插入元素,若容量已滿則阻塞等待
- 先獲取lock鎖(
lock.lock()) - 然后嘗試在隊(duì)首添加一個(gè)新節(jié)點(diǎn)(linkFirst(node))
- 若鏈接新節(jié)點(diǎn)失敗,則(
notFull.await())休眠等待直到等到”未滿“通知。
public void putFirst(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
while (!linkFirst(node))
notFull.await();
} finally {
lock.unlock();
}
}
linkLast 嘗試在隊(duì)列的頭部鏈接一個(gè)新節(jié)點(diǎn)。主要邏輯:
- 若隊(duì)列已滿,直接返回false(不能鏈接新節(jié)點(diǎn)) ;
- 將待入隊(duì)節(jié)點(diǎn)node作為新的頭節(jié)點(diǎn)添加在隊(duì)首(
first = node)并更新相關(guān)鏈接關(guān)系; - 元素計(jì)數(shù)加1(++count) ;
- 通知一個(gè)等待"非空"條件的線程(
notEmpty.signal()),最后返回true。
private boolean linkFirst(Node<E> node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)
//隊(duì)列已滿,不能鏈接新節(jié)點(diǎn)
return false;
Node<E> f = first;
node.next = f;//設(shè)置node的后繼節(jié)點(diǎn),它的后繼為原頭節(jié)點(diǎn)
first = node;////新的尾節(jié)點(diǎn)是剛添加的節(jié)點(diǎn)node
//更新原頭節(jié)點(diǎn)f的前驅(qū)節(jié)點(diǎn)
if (last == null)//隊(duì)列中沒(méi)有任何節(jié)點(diǎn),last first均未初始化
//隊(duì)列中只有一個(gè)節(jié)點(diǎn)(元素)時(shí),頭節(jié)點(diǎn)first 和尾節(jié)點(diǎn)last指定同一節(jié)點(diǎn)node
last = node;
else
f.prev = node;//原頭節(jié)點(diǎn)f的前驅(qū)節(jié)點(diǎn)是新頭節(jié)點(diǎn)(剛添加的節(jié)點(diǎn)node)
++count;//元素個(gè)數(shù)加1
notEmpty.signal();//通知一個(gè)等待"非空"條件的線程
return true;
}
offerFirst(E e)
offerFirst方法與putFirst類似,但offerFirst在檢測(cè)到隊(duì)列已滿時(shí)會(huì)直接返回false,不會(huì)阻塞等待。
public boolean offerFirst(E e) {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
return linkFirst(node);
} finally {
lock.unlock();
}
}
offerFirst(E e, long timeout, TimeUnit unit)
多參數(shù)的offerFirst方法,它可以看作putFirst的超時(shí)版本.
public boolean offerFirst(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (!linkFirst(node)) {
if (nanos <= 0) //在超時(shí)后,表明入隊(duì)失敗
return false;
nanos = notFull.awaitNanos(nanos);//超時(shí)等待
}
return true;
} finally {
lock.unlock();
}
}
刪除元素
在隊(duì)首刪除元素
remove pop poll take 等方法都是在隊(duì)列的尾部添加元素。它們將核心實(shí)現(xiàn)委托給 removeFirst 、pollFirst 、takeFirst等實(shí)現(xiàn)
public E take() throws InterruptedException {
return takeFirst();
}
public E poll() {
return pollFirst();
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
return pollFirst(timeout, unit);
}
public E remove() {
return removeFirst();
}
public E pop() {
return removeFirst();
}
takeFirst()
- takeLast先獲取lock鎖(
lock.lock()); - 然后嘗試在隊(duì)尾取消一個(gè)節(jié)點(diǎn)的鏈接(unlinkLast());
- 若取消鏈接失敗(隊(duì)列已空),則(
notEmpty.await())休眠等待直到等到”非空“通知。
public E takeLast() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E x;
while ( (x = unlinkLast()) == null)
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
unlinkLast()嘗試取消尾節(jié)點(diǎn)在鏈表中的鏈接
- 若隊(duì)列為空,直接返回null(不能取消鏈接) ;
- 將原尾節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)(Node<E> p = l.prev)作為新尾節(jié)點(diǎn)(
last = p)并更新相關(guān)鏈接關(guān)系; - 元素計(jì)數(shù)自減1(
--count) ; - 喚醒一個(gè)等待"未滿"條件的線程(
notFull.signal()),最后返回原尾節(jié)點(diǎn)中的元素(E item = l.item)。
private E unlinkLast() {
// assert lock.isHeldByCurrentThread();
Node<E> l = last;
if (l == null)
//鏈表未初始化,隊(duì)列中沒(méi)有任何元素,返回null
return null;
Node<E> p = l.prev;
E item = l.item;//保存尾節(jié)點(diǎn)的item,最終需要返回尾節(jié)點(diǎn)的item
l.item = null;//然后將原尾節(jié)點(diǎn)的item屬性清空
//prevn屬性自指,在使用迭代器時(shí)能標(biāo)識(shí)此節(jié)點(diǎn)已被刪除
l.prev = l; // help GC
last = p;//新尾節(jié)點(diǎn)是原尾節(jié)點(diǎn)的前驅(qū)繼節(jié)點(diǎn)
//設(shè)置新尾節(jié)點(diǎn)的后繼節(jié)點(diǎn)
if (p == null)//刪除尾節(jié)點(diǎn)前 鏈表中只有一個(gè)節(jié)點(diǎn)l
//將頭節(jié)點(diǎn)first、尾節(jié)點(diǎn)tail都設(shè)為null,鏈表中沒(méi)有任何節(jié)點(diǎn)了
first = null;
else//刪除尾節(jié)點(diǎn)前鏈表中至少有兩個(gè)節(jié)點(diǎn)(元素)
p.next = null;//將新尾節(jié)點(diǎn)的next設(shè)為null(尾節(jié)點(diǎn)沒(méi)有后繼節(jié)點(diǎn))
--count;//元素個(gè)數(shù)減1
notFull.signal();//喚醒一個(gè)等待”未滿“條件的線程
return item;
}
pollLast()
pollLast方法與takeLast類似,但pollLast在檢測(cè)到隊(duì)列為空時(shí)會(huì)直接返回null,不會(huì)阻塞等待。
public E pollLast() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return unlinkLast();
} finally {
lock.unlock();
}
}
pollLast(long timeout, TimeUnit unit)
可以看作是超時(shí)版本的takeLast,在超時(shí)之前無(wú)法出隊(duì)就返回null.
public E pollLast(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
E x;
while ( (x = unlinkLast()) == null) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return x;
} finally {
lock.unlock();
}
}
removeLast()
removeLast`直接委托pollLast實(shí)現(xiàn),若隊(duì)列為空,則拋出異常NoSuchElementException。
public E removeLast() {
E x = pollLast();
if (x == null) throw new NoSuchElementException();
return x;
}
刪除指定的元素
remove、 removeFirstOccurrence方法均是從隊(duì)列頭部開(kāi)始向后查找,在給定元素第一次出現(xiàn)的位置上將之刪除。
removeLastOccurrence是從隊(duì)列尾部開(kāi)始向前查找,在給定元素第一次出現(xiàn)的位置上將之刪除。
remove(Object o)
public boolean remove(Object o) {
return removeFirstOccurrence(o);
}
removeFirstOccurrence(Object o)
public boolean removeFirstOccurrence(Object o) {
if (o == null) return false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (Node<E> p = first; p != null; p = p.next) {//從隊(duì)列頭部開(kāi)始向后查找
if (o.equals(p.item)) {
unlink(p);//取消此節(jié)點(diǎn)在鏈表中的鏈接關(guān)系
return true;
}
}
return false;
} finally {
lock.unlock();
}
}
removeLastOccurrence(Object o)
public boolean removeLastOccurrence(Object o) {
if (o == null) return false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (Node<E> p = last; p != null; p = p.prev) {//隊(duì)列尾部開(kāi)始向前查找
if (o.equals(p.item)) {
unlink(p);
return true;
}
}
return false;
} finally {
lock.unlock();
}
}
unlink() 將一個(gè)節(jié)點(diǎn)從鏈表中刪除
void unlink(Node<E> x) {
// assert lock.isHeldByCurrentThread();
Node<E> p = x.prev;
Node<E> n = x.next;
if (p == null) {
//如果待刪除節(jié)點(diǎn)是頭節(jié)點(diǎn),
unlinkFirst();
} else if (n == null) {
//如果待刪除節(jié)點(diǎn)是尾節(jié)點(diǎn)
unlinkLast();
} else {//待刪除節(jié)點(diǎn)是非頭尾的中間節(jié)點(diǎn)
//通過(guò)next 、prev屬性,將刪除節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)p和待刪除節(jié)點(diǎn)的后繼節(jié)點(diǎn)n直接鏈接在一起,待刪除節(jié)點(diǎn)x已被排除在鏈表外
p.next = n;//待刪除節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)的next屬性設(shè)為 待刪除節(jié)點(diǎn)的后繼節(jié)點(diǎn)
n.prev = p;//待刪除節(jié)點(diǎn)的后繼節(jié)點(diǎn)的prev屬性設(shè)為 待刪除節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
x.item = null;//清空item
// Don't mess with x's links. They may still be in use by
// an iterator.
--count;
notFull.signal();
}
}
獲取隊(duì)列首尾元素
獲取隊(duì)首元素
- element、 getFirst返回隊(duì)列的首元素但不刪除,若隊(duì)列為空則拋出異常NoSuchElementException。
- peek 、peekFirst返回隊(duì)列的首元素但不刪除,若隊(duì)列為空則返回null.
public E element() {
return getFirst();
}
public E getFirst() {
E x = peekFirst();
if (x == null) throw new NoSuchElementException();
return x;
}
public E peek() {
return peekFirst();
}
public E peekFirst() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (first == null) ? null : first.item;
} finally {
lock.unlock();
}
}
獲取隊(duì)尾元素
- getLast返回隊(duì)列的尾元素但不刪除,若隊(duì)列為空則拋出異常NoSuchElementException。
- peekLast返回隊(duì)列的尾元素但不刪除,若隊(duì)列為空則返回null
public E getLast() {
E x = peekLast();
if (x == null) throw new NoSuchElementException();
return x;
}
public E peekLast() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (last == null) ? null : last.item;
} finally {
lock.unlock();
}
}
其他方法
contains(Object o)
contains方法,從頭到尾遍歷鏈表在隊(duì)列中查找是否存在此元素
public boolean contains(Object o) {
if (o == null) return false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (Node<E> p = first; p != null; p = p.next)
if (o.equals(p.item))
return true;
return false;
} finally {
lock.unlock();
}
}
size()
size方法返回隊(duì)列中元素的個(gè)數(shù)
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
clear()
clear清空隊(duì)列中的所有元素。其主要邏輯:
- 從頭到尾清空所有的鏈接關(guān)系(
f.prev = null;f.next = null;); - 將頭尾節(jié)點(diǎn)同時(shí)設(shè)空(
first = last = null); - 元素個(gè)數(shù)計(jì)數(shù)設(shè)為0(
count = 0); - 喚醒所有等待“未滿”條件的線程(
notFull.signalAll())。
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (Node<E> f = first; f != null; ) {
f.item = null;
Node<E> n = f.next;
f.prev = null;
f.next = null;
f = n;
}
first = last = null;
count = 0;
notFull.signalAll();
} finally {
lock.unlock();
}
}
迭代器
AbstractItr
AbstractItr是實(shí)現(xiàn)Iterator接口的一個(gè)抽象類,它為迭代器提供了很多默認(rèn)實(shí)現(xiàn),它是前序遍歷迭代器Itr和后序遍歷迭代器DescendingItr的父類。**

成員變量
Node<E> next; // 下次迭代的節(jié)點(diǎn)
E nextItem; // next()方法返回的元素
private Node<E> lastRet; // 上次迭代的節(jié)點(diǎn)
構(gòu)造方法
構(gòu)造方法將初始化next和nextItem屬性
AbstractItr() {
// set to initial position
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
next = firstNode();
nextItem = (next == null) ? null : next.item;
} finally {
lock.unlock();
}
}
抽象方法
抽象方法firstNode 、nextNode分別返回迭代器遍歷的第一個(gè)節(jié)點(diǎn)、下一個(gè)節(jié)點(diǎn)
abstract Node<E> firstNode();
abstract Node<E> nextNode(Node<E> n);
hasNext()
hasNext() 根據(jù)next屬性是否為空判定后面是否還有元素
public boolean hasNext() {
return next != null;
}
next()
next() 返回下一個(gè)元素
public E next() {
if (next == null)
throw new NoSuchElementException();
lastRet = next; //將next作為上次迭代的節(jié)點(diǎn)
E x = nextItem;
advance(); //更新next 和nextItem屬性
return x;
}
advance()
advance() 方法用于更新next 和nextItem屬性
void advance() {
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
// assert next != null;
next = succ(next);
nextItem = (next == null) ? null : next.item;
} finally {
lock.unlock();
}
}
succ()
succ返回指定節(jié)點(diǎn)的后繼節(jié)點(diǎn)
private Node<E> succ(Node<E> n) {
// Chains of deleted nodes ending in null or self-links
// are possible if multiple interior nodes are removed.
for (;;) {
Node<E> s = nextNode(n); //nextNode是AbstractItr的抽象方法,需要子類實(shí)現(xiàn), 它返回下個(gè)節(jié)點(diǎn)
if (s == null)
//n是尾節(jié)點(diǎn),所以s沒(méi)有后繼節(jié)點(diǎn),返回null
return null;
else if (s.item != null)
//n是非尾節(jié)點(diǎn),所以其后繼節(jié)點(diǎn)s的item不為空 ,返回s
return s;
else if (s == n)
//s.item==null 且 n.next==n
//item為空、next屬性自指,表示原頭(尾)節(jié)點(diǎn)n邏輯上已被刪除,first(last)更新延遲
//獲取最新的first(last)
return firstNode();
else
//s.item==null && n.next!=n
//item為空但next屬性不自指 ,表示節(jié)點(diǎn)s在鏈表(非頭尾)中間位置,在邏輯s上已被刪除,
//(可能是remove(Object)方法在隊(duì)列中部刪除了元素)需要繼續(xù)向下查找有效節(jié)點(diǎn)
n = s;
}
}
remove()
remove方法移除當(dāng)前迭代的元素,此方法與外部類的remove方法類似。
public void remove() {
Node<E> n = lastRet;
if (n == null)
throw new IllegalStateException();
lastRet = null;//將lastRet設(shè)為null,可指示這個(gè)元素節(jié)點(diǎn)被刪除
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
if (n.item != null)
unlink(n);//外部類的方法,將n節(jié)點(diǎn)從鏈表中刪除
} finally {
lock.unlock();
}
}
Itr與DescendingItr
Itr和 DescendingItr都實(shí)現(xiàn)了類型的抽象方法firstNode 、nextNode。Itr代表前序迭代器,從頭節(jié)點(diǎn)開(kāi)始向后遍歷,firstNode方法返回頭節(jié)點(diǎn),nextNode返回指定節(jié)點(diǎn)的后繼節(jié)點(diǎn)。而DescendingItr代表后序迭代器,從尾節(jié)點(diǎn)開(kāi)始向前遍歷,firstNode方法返回尾節(jié)點(diǎn),nextNode返回指定節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
/** Forward iterator */
private class Itr extends AbstractItr {
Node<E> firstNode() { return first; }
Node<E> nextNode(Node<E> n) { return n.next; }
}
/** Descending iterator */
private class DescendingItr extends AbstractItr {
Node<E> firstNode() { return last; }
Node<E> nextNode(Node<E> n) { return n.prev; }
}
示例Demo
package com.niuh.deque;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingDeque;
/**
* <p>
* LinkedBlockingDeque示例
* </p>
*/
public class LinkedBlockingDequeDemo {
public static void main(String[] args) {
/**
* 1.1、LinkedBlockingDeque():
* 創(chuàng)建一個(gè)容量為 Integer.MAX_VALUE 的 LinkedBlockingDeque。
* 1.2、LinkedBlockingDeque(int capacity):
* 創(chuàng)建一個(gè)具有給定(固定)容量的 LinkedBlockingDeque。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque = new LinkedBlockingDeque<>();
/**
* 1、add(E e):在不違反容量限制的情況下,將指定的元素插入此雙端隊(duì)列的末尾,返回值為Boolean。
*/
Boolean addBoolean = linkedBlockingDeque.add(5);
System.out.println("是否添加成功:" + addBoolean);
/**
* 2、addFirst(E e):如果立即可行且不違反容量限制,則將指定的元素插入此雙端隊(duì)列的開(kāi)頭;
* 如果當(dāng)前沒(méi)有空間可用,則拋出 IllegalStateException。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque1 = new LinkedBlockingDeque<>();
linkedBlockingDeque1.addFirst(1);
linkedBlockingDeque1.addFirst(2);
linkedBlockingDeque1.addFirst(3);
/**
* 3、iterator():返回在此雙端隊(duì)列元素上以恰當(dāng)順序進(jìn)行迭代的迭代器。
*/
Iterator<Integer> iterator = linkedBlockingDeque1.iterator();
while (iterator.hasNext()) {
System.out.println("Iterator的addFirst結(jié)果:" + iterator.next());
}
/**
* 4、addLast(E e) :如果立即可行且不違反容量限制,則將指定的元素插入此雙端隊(duì)列的末尾;
* 如果當(dāng)前沒(méi)有空間可用,則拋出 IllegalStateException
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque2 = new LinkedBlockingDeque<>();
linkedBlockingDeque2.addLast(1);
linkedBlockingDeque2.addLast(2);
linkedBlockingDeque2.addLast(3);
Iterator<Integer> iterator1 = linkedBlockingDeque2.iterator();
while (iterator1.hasNext()) {
System.out.println("Iterator的addLast結(jié)果:" + iterator1.next());
}
/**
* 5、clear():以原子方式 (atomically) 從此雙端隊(duì)列移除所有元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque3 = new LinkedBlockingDeque<>();
linkedBlockingDeque3.add(1);
linkedBlockingDeque3.add(2);
linkedBlockingDeque3.add(3);
linkedBlockingDeque3.clear();
System.out.println("================");
Iterator<Integer> iterator2 = linkedBlockingDeque3.iterator();
while (iterator2.hasNext()) {
System.out.println("Iterator的clear結(jié)果:" + iterator2.next());
}
System.out.println("================");
/**
* 6、contains(Object o) :如果此雙端隊(duì)列包含指定的元素,則返回 true
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque4 = new LinkedBlockingDeque<>();
linkedBlockingDeque4.add(1);
linkedBlockingDeque4.add(2);
linkedBlockingDeque4.add(3);
Boolean contains3Boolean = linkedBlockingDeque4.contains(3);
Boolean contains4Boolean = linkedBlockingDeque4.contains(4);
System.out.println("是否包含3:" + contains3Boolean + " 是否包含4:" + contains4Boolean);
/**
* 7、element():獲取但不移除此雙端隊(duì)列表示的隊(duì)列的頭部
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque5 = new LinkedBlockingDeque<>();
linkedBlockingDeque5.add(1);
linkedBlockingDeque5.add(2);
linkedBlockingDeque5.add(3);
Integer elementResult = linkedBlockingDeque5.element();
System.out.println("隊(duì)列的頭部: " + elementResult);
/**
* 8、getFirst() :獲取,但不移除此雙端隊(duì)列的第一個(gè)元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque6 = new LinkedBlockingDeque<>();
linkedBlockingDeque6.add(1);
linkedBlockingDeque6.add(2);
linkedBlockingDeque6.add(3);
Integer firstResult = linkedBlockingDeque6.getFirst();
System.out.println("雙端隊(duì)列的第一個(gè)元素: " + firstResult);
/**
* 9、 getLast() :獲取,但不移除此雙端隊(duì)列的最后一個(gè)元素
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque7 = new LinkedBlockingDeque<>();
linkedBlockingDeque7.add(3);
linkedBlockingDeque7.add(4);
linkedBlockingDeque7.add(5);
Integer lastResult = linkedBlockingDeque7.getLast();
System.out.println("雙端隊(duì)列的最后一個(gè)元素: " + lastResult);
/**
* 10.1、offer(E e) :如果立即可行且不違反容量限制,
* 則將指定的元素插入此雙端隊(duì)列表示的隊(duì)列中(即此雙端隊(duì)列的尾部),
* 并在成功時(shí)返回 true;如果當(dāng)前沒(méi)有空間可用,則返回 false
*
* 10.2、offer(E e, long timeout, TimeUnit unit) :
* 將指定的元素插入此雙端隊(duì)列表示的隊(duì)列中(即此雙端隊(duì)列的尾部),
* 必要時(shí)將在指定的等待時(shí)間內(nèi)一直等待可用空間,返回值為Boolean。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque8 = new LinkedBlockingDeque<>();
linkedBlockingDeque8.offer(1);
linkedBlockingDeque8.offer(2);
linkedBlockingDeque8.offer(3);
Iterator<Integer> iterator3 = linkedBlockingDeque8.iterator();
while (iterator3.hasNext()) {
System.out.println("Iterator的offer結(jié)果:" + iterator3.next());
}
/**
* 11.1、offerFirst(E e) :
* 如果立即可行且不違反容量限制,則將指定的元素插入此雙端隊(duì)列的開(kāi)頭,
* 并在成功時(shí)返回 true;如果當(dāng)前沒(méi)有空間可用,則返回 false。
* 11.2、fferFirst(E e, long timeout, TimeUnit unit):
* 將指定的元素插入此雙端隊(duì)列的開(kāi)頭,必要時(shí)將在指定的等待時(shí)間內(nèi)等待可用空間。
* 返回值為Boolean。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque9 = new LinkedBlockingDeque<>();
linkedBlockingDeque9.offerFirst(1);
linkedBlockingDeque9.offerFirst(2);
linkedBlockingDeque9.offerFirst(3);
Iterator<Integer> iterator4 = linkedBlockingDeque9.iterator();
while (iterator4.hasNext()) {
System.out.println("Iterator的offerFirst結(jié)果:" + iterator4.next());
}
/**
* 12.1、offerLast(E e):
* 如果立即可行且不違反容量限制,則將指定的元素插入此雙端隊(duì)列的末尾,并在成功時(shí)返回 true;如果當(dāng)前沒(méi)有空間可用,則返回 false。
* 12.2、offerLast(E e, long timeout, TimeUnit unit):
* 將指定的元素插入此雙端隊(duì)列的末尾,必要時(shí)將在指定的等待時(shí)間內(nèi)等待可用空間。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque10 = new LinkedBlockingDeque<>();
linkedBlockingDeque10.offerLast(1);
linkedBlockingDeque10.offerLast(2);
linkedBlockingDeque10.offerLast(3);
Iterator<Integer> iterator5 = linkedBlockingDeque10.iterator();
while (iterator5.hasNext()) {
System.out.println("Iterator的offerLast結(jié)果:" + iterator5.next());
}
/**
* 13、peek():獲取但不移除此雙端隊(duì)列表示的隊(duì)列的頭部(即此雙端隊(duì)列的第一個(gè)元素);
* 如果此雙端隊(duì)列為空,則返回 null
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque11 = new LinkedBlockingDeque<>();
linkedBlockingDeque11.add(1);
linkedBlockingDeque11.add(2);
linkedBlockingDeque11.add(3);
Integer peekResult = linkedBlockingDeque11.peek();
System.out.println("peekResult的結(jié)果:" + peekResult);
/**
* 14、peekFirst():獲取,但不移除此雙端隊(duì)列的第一個(gè)元素;如果此雙端隊(duì)列為空,則返回 null。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque12 = new LinkedBlockingDeque<>();
linkedBlockingDeque12.add(3);
linkedBlockingDeque12.add(4);
linkedBlockingDeque12.add(5);
Integer peekFirstResult = linkedBlockingDeque12.peekFirst();
System.out.println("peekFirstResult的結(jié)果:" + peekFirstResult);
/**
* 15、peekLast() :獲取,但不移除此雙端隊(duì)列的最后一個(gè)元素;如果此雙端隊(duì)列為空,則返回 null。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque13 = new LinkedBlockingDeque<>();
linkedBlockingDeque13.add(6);
linkedBlockingDeque13.add(7);
linkedBlockingDeque13.add(8);
Integer peekLastResult = linkedBlockingDeque13.peekLast();
System.out.println("peekLastResult的結(jié)果:" + peekLastResult);
/**
* 16.1、poll() :獲取并移除此雙端隊(duì)列表示的隊(duì)列的頭部(即此雙端隊(duì)列的第一個(gè)元素);
* 如果此雙端隊(duì)列為空,則返回 null。
* 16.2、poll(long timeout, TimeUnit unit):
* 獲取并移除此雙端隊(duì)列表示的隊(duì)列的頭部(即此雙端隊(duì)列的第一個(gè)元素),
* 如有必要將在指定的等待時(shí)間內(nèi)等待可用元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque14 = new LinkedBlockingDeque<>();
linkedBlockingDeque14.add(9);
linkedBlockingDeque14.add(10);
linkedBlockingDeque14.add(11);
Integer pollResult = linkedBlockingDeque14.poll();
System.out.println("peekLastResult的結(jié)果:" + pollResult);
System.out.println("linkedBlockingDeque14是否還包含9:" + linkedBlockingDeque14.contains(9));
/**
* 17.1、pollFirst() :
* 獲取并移除此雙端隊(duì)列的第一個(gè)元素;如果此雙端隊(duì)列為空,則返回 null。
* 17.2、pollFirst(long timeout, TimeUnit unit) :
* 獲取并移除此雙端隊(duì)列的第一個(gè)元素,必要時(shí)將在指定的等待時(shí)間等待可用元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque15 = new LinkedBlockingDeque<>();
linkedBlockingDeque15.addFirst(9);
linkedBlockingDeque15.addFirst(10);
linkedBlockingDeque15.addFirst(11);
Integer pollFirstResult = linkedBlockingDeque15.pollFirst();
System.out.println("pollFirstResult的結(jié)果:" + pollFirstResult);
System.out.println("linkedBlockingDeque15是否還包含11:" + linkedBlockingDeque15.contains(11));
/**
* 18.1、pollLast()
* 獲取并移除此雙端隊(duì)列的最后一個(gè)元素;如果此雙端隊(duì)列為空,則返回 null。
* 18.2、pollLast(long timeout, TimeUnit unit)
* 獲取并移除此雙端隊(duì)列的最后一個(gè)元素,必要時(shí)將在指定的等待時(shí)間內(nèi)等待可用元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque16 = new LinkedBlockingDeque<>();
linkedBlockingDeque16.add(9);
linkedBlockingDeque16.add(10);
linkedBlockingDeque16.add(11);
Integer pollLastResult = linkedBlockingDeque16.pollLast();
System.out.println("pollLastResult的結(jié)果:" + pollLastResult);
System.out.println("linkedBlockingDeque16是否還包含11:" + linkedBlockingDeque16.contains(11));
/**
* 19、 pop() :從此雙端隊(duì)列所表示的堆棧中彈出一個(gè)元素(移除效果)
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque17 = new LinkedBlockingDeque<>();
linkedBlockingDeque17.addFirst(1);
linkedBlockingDeque17.addFirst(2);
linkedBlockingDeque17.addFirst(3);
Integer pop1Result = linkedBlockingDeque17.pop();
System.out.println("pop2Result的結(jié)果:" + pop1Result);
Integer pop2Result = linkedBlockingDeque17.pop();
System.out.println("pop2Result的結(jié)果:" + pop2Result);
System.out.println("linkedBlockingDeque17是否還包含2:" + linkedBlockingDeque17.contains(2));
/**
* 20、push(E e) :將元素推入此雙端隊(duì)列表示的棧。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque18 = new LinkedBlockingDeque<>();
linkedBlockingDeque18.push(1);
linkedBlockingDeque18.push(2);
linkedBlockingDeque18.push(3);
Iterator<Integer> iterator6 = linkedBlockingDeque18.iterator();
while (iterator6.hasNext()) {
System.out.println("Iterator的push結(jié)果:" + iterator6.next());
}
/**
* 21、put(E e) :將指定的元素插入此雙端隊(duì)列表示的隊(duì)列中(即此雙端隊(duì)列的尾部),
* 必要時(shí)將一直等待可用空間。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque19 = new LinkedBlockingDeque<>();
try {
linkedBlockingDeque19.put(1);
linkedBlockingDeque19.put(2);
linkedBlockingDeque19.put(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Iterator<Integer> iterator7 = linkedBlockingDeque19.iterator();
while (iterator7.hasNext()) {
System.out.println("Iterator的put結(jié)果:" + iterator7.next());
}
/**
* 22、putFirst(E e) :將指定的元素插入此雙端隊(duì)列的開(kāi)頭,必要時(shí)將一直等待可用空間。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque20 = new LinkedBlockingDeque<>();
try {
linkedBlockingDeque20.putFirst(1);
linkedBlockingDeque20.putFirst(2);
linkedBlockingDeque20.putFirst(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Iterator<Integer> iterator8 = linkedBlockingDeque20.iterator();
while (iterator8.hasNext()) {
System.out.println("Iterator的putFirst結(jié)果:" + iterator8.next());
}
/**
* 23、putLast(E e) :將指定的元素插入此雙端隊(duì)列的末尾,必要時(shí)將一直等待可用空間。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque21 = new LinkedBlockingDeque<>();
try {
linkedBlockingDeque21.putLast(1);
linkedBlockingDeque21.putLast(2);
linkedBlockingDeque21.putLast(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Iterator<Integer> iterator9 = linkedBlockingDeque21.iterator();
while (iterator9.hasNext()) {
System.out.println("Iterator的putLast結(jié)果:" + iterator9.next());
}
/**
* 24、remove():獲取并移除此雙端隊(duì)列表示的隊(duì)列的頭部。返回一個(gè)E
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque22 = new LinkedBlockingDeque<>();
linkedBlockingDeque22.addFirst(1);
linkedBlockingDeque22.addFirst(2);
linkedBlockingDeque22.addFirst(3);
Integer removeResult = linkedBlockingDeque22.remove();
System.out.println("removeResult的結(jié)果:" + removeResult);
System.out.println("linkedBlockingDeque22是否還包含3:" + linkedBlockingDeque22.contains(3));
/**
* 25、remove(Object o) :從此雙端隊(duì)列移除第一次出現(xiàn)的指定元素,返回值為Boolean。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque23 = new LinkedBlockingDeque<>();
linkedBlockingDeque23.addFirst(1);
linkedBlockingDeque23.addFirst(2);
linkedBlockingDeque23.addFirst(3);
Boolean removeBoolean = linkedBlockingDeque23.remove(3);
System.out.println("是否remove了3 :" + removeBoolean);
/**
* 26、removeFirst():獲取并移除此雙端隊(duì)列第一個(gè)元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque24 = new LinkedBlockingDeque<>();
linkedBlockingDeque24.addLast(1);
linkedBlockingDeque24.addLast(2);
linkedBlockingDeque24.addLast(3);
Integer removeFirstResult = linkedBlockingDeque24.removeFirst();
System.out.println("removeFirstResult:" + removeFirstResult);
System.out.println("linkedBlockingDeque24是否還包含1:" + linkedBlockingDeque24.contains(1));
/**
* 27、 removeLast():獲取并移除此雙端隊(duì)列的最后一個(gè)元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque25 = new LinkedBlockingDeque<>();
linkedBlockingDeque25.addLast(4);
linkedBlockingDeque25.addLast(5);
linkedBlockingDeque25.addLast(6);
Integer removeLastResult = linkedBlockingDeque25.removeLast();
System.out.println("removeLastResult:" + removeLastResult);
System.out.println("linkedBlockingDeque25是否還包含6:" + linkedBlockingDeque25.contains(6));
/**
* 28、take():獲取并移除此雙端隊(duì)列表示的隊(duì)列的頭部(即此雙端隊(duì)列的第一個(gè)元素),
* 必要時(shí)將一直等待可用元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque26 = new LinkedBlockingDeque<>();
linkedBlockingDeque26.push(4);
linkedBlockingDeque26.push(5);
linkedBlockingDeque26.push(6);
Integer takeResult = null;
try {
takeResult = linkedBlockingDeque26.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("takeResult:" + takeResult);
System.out.println("linkedBlockingDeque26是否還包含6:" + linkedBlockingDeque26.contains(6));
/**
* 29、takeFirst() :獲取并移除此雙端隊(duì)列的第一個(gè)元素,必要時(shí)將一直等待可用元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque27 = new LinkedBlockingDeque<>();
linkedBlockingDeque27.push(7);
linkedBlockingDeque27.push(8);
linkedBlockingDeque27.push(9);
Integer takeFirstResult = null;
try {
takeFirstResult = linkedBlockingDeque27.takeFirst();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("takeFirst:" + takeFirstResult);
System.out.println("linkedBlockingDeque27是否還包含9:" + linkedBlockingDeque27.contains(9));
/**
* 30、takeLast():獲取并移除此雙端隊(duì)列的最后一個(gè)元素,必要時(shí)將一直等待可用元素。
*/
LinkedBlockingDeque<Integer> linkedBlockingDeque28 = new LinkedBlockingDeque<>();
linkedBlockingDeque28.push(10);
linkedBlockingDeque28.push(11);
linkedBlockingDeque28.push(12);
Integer takeLastResult = null;
try {
takeLastResult = linkedBlockingDeque28.takeLast();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("takeLastResult:" + takeLastResult);
System.out.println("linkedBlockingDeque28是否還包含10:" + linkedBlockingDeque28.contains(10));
}
}
總結(jié)
- LinkedBlockingDeque 內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是一個(gè)雙向鏈表,在頭尾位置它均能插入、刪除節(jié)點(diǎn)(元素),同時(shí)因?yàn)槊總€(gè)節(jié)點(diǎn)都要保存前驅(qū)、后繼節(jié)點(diǎn)的引用,它能夠(前序、后序)雙向遍歷鏈表。也因?yàn)樵谄漕^、尾位置均能出隊(duì),它可用在工作竊取算法中;
- LinkedBlockingDeque 在構(gòu)造方法初始化后,頭尾節(jié)點(diǎn)均為 null,未初始化;而 LinkedBlockingQueue 在構(gòu)造方法初始化后,頭尾節(jié)點(diǎn)會(huì)被初始化,它們指向同一個(gè)節(jié)點(diǎn)(item 為 null);
- LinkedBlockingDeque 的頭節(jié)點(diǎn)first會(huì)保存元素,first.item 永不為空;而 LinkedBlockingQueue 的頭節(jié)點(diǎn)first 不保存元素,first.item 一直為空,頭節(jié)點(diǎn)的后繼節(jié)點(diǎn) first.next 才是鏈表中保存首元素的節(jié)點(diǎn)。
- 和LinkedBlockingQueue一樣,LinkedBlockingDeque 在原頭(尾)出隊(duì)后利用 next(prev)屬性自指標(biāo)識(shí)此節(jié)點(diǎn)在邏輯上已被刪除;
LinkedBlockingDeque與LinkedList區(qū)別
package com.niuh.deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingDeque;
/*
* LinkedBlockingDeque是“線程安全”的隊(duì)列,而LinkedList是非線程安全的。
*
* 下面是“多個(gè)線程同時(shí)操作并且遍歷queue”的示例
* (1) 當(dāng)queue是LinkedBlockingDeque對(duì)象時(shí),程序能正常運(yùn)行。
* (2) 當(dāng)queue是LinkedList對(duì)象時(shí),程序會(huì)產(chǎn)生ConcurrentModificationException異常。
*
*/
public class LinkedBlockingDequeRunner {
// TODO: queue是LinkedList對(duì)象時(shí),程序會(huì)出錯(cuò)。
// private static Queue<String> queue = new LinkedList<String>();
private static Queue<String> queue = new LinkedBlockingDeque<String>();
public static void main(String[] args) {
// 同時(shí)啟動(dòng)兩個(gè)線程對(duì)queue進(jìn)行操作!
new MyThread("A").start();
new MyThread("B").start();
}
private static void printAll() {
String value;
Iterator iter = queue.iterator();
while (iter.hasNext()) {
value = (String) iter.next();
System.out.print(value + ", ");
}
System.out.println();
}
private static class MyThread extends Thread {
MyThread(String name) {
super(name);
}
@Override
public void run() {
int i = 0;
while (i++ < 6) {
// “線程名” + "-" + "序號(hào)"
String val = Thread.currentThread().getName() + i;
queue.add(val);
// 通過(guò)“Iterator”遍歷queue。
printAll();
}
}
}
}
輸出結(jié)果:
A1,
A1, A2,
A1, A2, A3,
A1, A2, A3, A4,
A1, A2, A3, A4, A5,
A1, A2, A3, A4, A5, A6,
A1, A2, A3, A4, A5, A6, B1,
A1, A2, A3, A4, A5, A6, B1, B2,
A1, A2, A3, A4, A5, A6, B1, B2, B3,
A1, A2, A3, A4, A5, A6, B1, B2, B3, B4,
A1, A2, A3, A4, A5, A6, B1, B2, B3, B4, B5,
A1, A2, A3, A4, A5, A6, B1, B2, B3, B4, B5, B6,
結(jié)果說(shuō)明:示例程序中,啟動(dòng)兩個(gè)線程(線程A和線程B)分別對(duì)LinkedBlockingDeque進(jìn)行操作:
- 以線程A而言,它會(huì)先獲取“線程名”+“序號(hào)”,然后將該字符串添加到LinkedBlockingDeque中;
- 接著,遍歷并輸出LinkedBlockingDeque中的全部元素。
- 線程B的操作和線程A一樣,只不過(guò)線程B的名字和線程A的名字不同。
- 當(dāng)queue是LinkedBlockingDeque對(duì)象時(shí),程序能正常運(yùn)行。
- 如果將queue改為L(zhǎng)inkedList時(shí),程序會(huì)產(chǎn)生ConcurrentModificationException異常。
PS:以上代碼提交在 Github :https://github.com/Niuh-Study/niuh-juc-final.git
PS:這里有一個(gè)技術(shù)交流群(QQ群:1158819530),方便大家一起交流,持續(xù)學(xué)習(xí),共同進(jìn)步,有需要的可以加一下。
文章持續(xù)更新,可以公眾號(hào)搜一搜「 一角錢技術(shù) 」第一時(shí)間閱讀, 本文 GitHub org_hejianhui/JavaStudy 已經(jīng)收錄,歡迎 Star。