阻塞隊(duì)列 — LinkedBlockingDeque源碼分析

點(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ō)明

  1. LinkedBlockingDeque繼承于AbstractQueue,它本質(zhì)上是一個(gè)支持FIFO和FILO的雙向的隊(duì)列。
  2. LinkedBlockingDeque實(shí)現(xiàn)了BlockingDeque接口,它支持多線程并發(fā)。當(dāng)多線程競(jìng)爭(zhēng)同一個(gè)資源時(shí),某線程獲取到該資源之后,其它線程需要阻塞等待。
  3. 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 、offerLastadd``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)。主要邏輯:

  1. 若隊(duì)列已滿,直接返回false(不能鏈接新節(jié)點(diǎn)) ;
  2. 將待入隊(duì)節(jié)點(diǎn)node作為新的尾節(jié)點(diǎn)添加在隊(duì)尾(last = node)并更新相關(guān)鏈接關(guān)系;
  3. 元素計(jì)數(shù)加1(++count) ;
  4. 喚醒一個(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)。主要邏輯:

  1. 若隊(duì)列已滿,直接返回false(不能鏈接新節(jié)點(diǎn)) ;
  2. 將待入隊(duì)節(jié)點(diǎn)node作為新的頭節(jié)點(diǎn)添加在隊(duì)首(first = node)并更新相關(guān)鏈接關(guān)系;
  3. 元素計(jì)數(shù)加1(++count) ;
  4. 通知一個(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)在鏈表中的鏈接

  1. 若隊(duì)列為空,直接返回null(不能取消鏈接) ;
  2. 將原尾節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)(Node<E> p = l.prev)作為新尾節(jié)點(diǎn)(last = p)并更新相關(guān)鏈接關(guān)系;
  3. 元素計(jì)數(shù)自減1(--count) ;
  4. 喚醒一個(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:以上代碼提交在 Githubhttps://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。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容