日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java多线程(六)之Deque与LinkedBlockingDeque深入分析

發(fā)布時(shí)間:2024/1/17 java 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java多线程(六)之Deque与LinkedBlockingDeque深入分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、雙向隊(duì)列Deque

?

Queue除了前面介紹的實(shí)現(xiàn)外,還有一種雙向的Queue實(shí)現(xiàn)Deque。這種隊(duì)列允許在隊(duì)列頭和尾部進(jìn)行入隊(duì)出隊(duì)操作,因此在功能上比Queue顯然要更復(fù)雜。下圖描述的是Deque的完整體系圖。需要說(shuō)明的是LinkedList也已經(jīng)加入了Deque的一部分(LinkedList是從jdk1.2 開(kāi)始就存在數(shù)據(jù)結(jié)構(gòu))。

?

Deque在Queue的基礎(chǔ)上增加了更多的操作方法。

從上圖可以看到,Deque不僅具有FIFO的Queue實(shí)現(xiàn),也有FILO的實(shí)現(xiàn),也就是不僅可以實(shí)現(xiàn)隊(duì)列,也可以實(shí)現(xiàn)一個(gè)堆棧。

同時(shí)在Deque的體系結(jié)構(gòu)圖中可以看到,實(shí)現(xiàn)一個(gè)Deque可以使用數(shù)組(ArrayDeque),同時(shí)也可以使用鏈表(LinkedList),還可以同實(shí)現(xiàn)一個(gè)支持阻塞的線程安全版本隊(duì)列LinkedBlockingDeque。

?

1、ArrayDeque實(shí)現(xiàn)Deque

?

?

對(duì)于數(shù)組實(shí)現(xiàn)的Deque來(lái)說(shuō),數(shù)據(jù)結(jié)構(gòu)上比較簡(jiǎn)單,只需要一個(gè)存儲(chǔ)數(shù)據(jù)的數(shù)組以及頭尾兩個(gè)索引即可。由于數(shù)組是固定長(zhǎng)度的,所以很容易就得到數(shù)組的頭和尾,那么對(duì)于數(shù)組的操作只需要移動(dòng)頭和尾的索引即可。

特別說(shuō)明的是ArrayDeque并不是一個(gè)固定大小的隊(duì)列,每次隊(duì)列滿了以后就將隊(duì)列容量擴(kuò)大一倍(doubleCapacity()),因此加入一個(gè)元素總是能成功,而且也不會(huì)拋出一個(gè)異常。也就是說(shuō)ArrayDeque是一個(gè)沒(méi)有容量限制的隊(duì)列。

同樣繼續(xù)性能的考慮,使用System.arraycopy復(fù)制一個(gè)數(shù)組比循環(huán)設(shè)置要高效得多。

?

1.1、ArrayDeque的源碼解析

?

?

  • //數(shù)組雙端隊(duì)列ArrayDeque的源碼解析

  • public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable{

  • /**

  • * 存放隊(duì)列元素的數(shù)組,數(shù)組的長(zhǎng)度為“2的指數(shù)”

  • */

  • private transient E[] elements;

  • /**

  • *隊(duì)列的頭部索引位置,(被remove()或pop()操作的位置),當(dāng)為空隊(duì)列時(shí),首尾index相同

  • */

  • private transient int head;

  • /**

  • * 隊(duì)列的尾部索引位置,(被 addLast(E), add(E), 或 push(E)操作的位置).

  • */

  • private transient int tail;

  • /**

  • * 隊(duì)列的最小容量(大小必須為“2的指數(shù)”)

  • */

  • private static final int MIN_INITIAL_CAPACITY = 8;

  • // ****** Array allocation and resizing utilities ******

  • /**

  • * 根據(jù)所給的數(shù)組長(zhǎng)度,得到一個(gè)比該長(zhǎng)度大的最小的2^p的真實(shí)長(zhǎng)度,并建立真實(shí)長(zhǎng)度的空數(shù)組

  • */

  • private void allocateElements(int numElements) {

  • int initialCapacity = MIN_INITIAL_CAPACITY;

  • if (numElements >= initialCapacity) {

  • initialCapacity = numElements;

  • initialCapacity |= (initialCapacity >>> 1);

  • initialCapacity |= (initialCapacity >>> 2);

  • initialCapacity |= (initialCapacity >>> 4);

  • initialCapacity |= (initialCapacity >>> 8);

  • initialCapacity |= (initialCapacity >>> 16);

  • initialCapacity++;

  • if (initialCapacity < 0) // Too many elements, must back off

  • initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements

  • }

  • elements = (E[]) new Object[initialCapacity];

  • }

  • /**

  • * 當(dāng)隊(duì)列首尾指向同一個(gè)引用時(shí),擴(kuò)充隊(duì)列的容量為原來(lái)的兩倍,并對(duì)元素重新定位到新數(shù)組中

  • */

  • private void doubleCapacity() {

  • assert head == tail;

  • int p = head;

  • int n = elements.length;

  • int r = n - p; // number of elements to the right of p

  • int newCapacity = n << 1;

  • if (newCapacity < 0)

  • throw new IllegalStateException("Sorry, deque too big");

  • Object[] a = new Object[newCapacity];

  • System.arraycopy(elements, p, a, 0, r);

  • System.arraycopy(elements, 0, a, r, p);

  • elements = (E[])a;

  • head = 0;

  • tail = n;

  • }

  • /**

  • * 拷貝隊(duì)列中的元素到新數(shù)組中

  • */

  • private <T> T[] copyElements(T[] a) {

  • if (head < tail) {

  • System.arraycopy(elements, head, a, 0, size());

  • } else if (head > tail) {

  • int headPortionLen = elements.length - head;

  • System.arraycopy(elements, head, a, 0, headPortionLen);

  • System.arraycopy(elements, 0, a, headPortionLen, tail);

  • }

  • return a;

  • }

  • /**

  • * 默認(rèn)構(gòu)造隊(duì)列,初始化一個(gè)長(zhǎng)度為16的數(shù)組

  • */

  • public ArrayDeque() {

  • elements = (E[]) new Object[16];

  • }

  • /**

  • * 指定元素個(gè)數(shù)的構(gòu)造方法

  • */

  • public ArrayDeque(int numElements) {

  • allocateElements(numElements);

  • }

  • /**

  • * 用一個(gè)集合作為參數(shù)的構(gòu)造方法

  • */

  • public ArrayDeque(Collection<? extends E> c) {

  • allocateElements(c.size());

  • addAll(c);

  • }

  • //插入和刪除的方法主要是: addFirst(),addLast(), pollFirst(), pollLast()。

  • //其他的方法依賴于這些實(shí)現(xiàn)。

  • /**

  • * 在雙端隊(duì)列的前端插入元素,元素為null拋異常

  • */

  • public void addFirst(E e) {

  • if (e == null)

  • throw new NullPointerException();

  • elements[head = (head - 1) & (elements.length - 1)] = e;

  • if (head == tail)

  • doubleCapacity();

  • }

  • /**

  • *在雙端隊(duì)列的末端插入元素,元素為null拋異常

  • */

  • public void addLast(E e) {

  • if (e == null)

  • throw new NullPointerException();

  • elements[tail] = e;

  • if ( (tail = (tail + 1) & (elements.length - 1)) == head)

  • doubleCapacity();

  • }

  • /**

  • * 在前端插入,調(diào)用addFirst實(shí)現(xiàn),返回boolean類型

  • */

  • public boolean offerFirst(E e) {

  • addFirst(e);

  • return true;

  • }

  • /**

  • * 在末端插入,調(diào)用addLast實(shí)現(xiàn),返回boolean類型

  • */

  • public boolean offerLast(E e) {

  • addLast(e);

  • return true;

  • }

  • /**

  • * 刪除前端,調(diào)用pollFirst實(shí)現(xiàn)

  • */

  • public E removeFirst() {

  • E x = pollFirst();

  • if (x == null)

  • throw new NoSuchElementException();

  • return x;

  • }

  • /**

  • * 刪除后端,調(diào)用pollLast實(shí)現(xiàn)

  • */

  • public E removeLast() {

  • E x = pollLast();

  • if (x == null)

  • throw new NoSuchElementException();

  • return x;

  • }

  • //前端出對(duì)(刪除前端)

  • public E pollFirst() {

  • int h = head;

  • E result = elements[h]; // Element is null if deque empty

  • if (result == null)

  • return null;

  • elements[h] = null; // Must null out slot

  • head = (h + 1) & (elements.length - 1);

  • return result;

  • }

  • //后端出對(duì)(刪除后端)

  • public E pollLast() {

  • int t = (tail - 1) & (elements.length - 1);

  • E result = elements[t];

  • if (result == null)

  • return null;

  • elements[t] = null;

  • tail = t;

  • return result;

  • }

  • /**

  • * 得到前端頭元素

  • */

  • public E getFirst() {

  • E x = elements[head];

  • if (x == null)

  • throw new NoSuchElementException();

  • return x;

  • }

  • /**

  • * 得到末端尾元素

  • */

  • public E getLast() {

  • E x = elements[(tail - 1) & (elements.length - 1)];

  • if (x == null)

  • throw new NoSuchElementException();

  • return x;

  • }

  • public E peekFirst() {

  • return elements[head]; // elements[head] is null if deque empty

  • }

  • public E peekLast() {

  • return elements[(tail - 1) & (elements.length - 1)];

  • }

  • /**

  • * 移除此雙端隊(duì)列中第一次出現(xiàn)的指定元素(當(dāng)從頭部到尾部遍歷雙端隊(duì)列時(shí))。

  • */

  • public boolean removeFirstOccurrence(Object o) {

  • if (o == null)

  • return false;

  • int mask = elements.length - 1;

  • int i = head;

  • E x;

  • while ( (x = elements[i]) != null) {

  • if (o.equals(x)) {

  • delete(i);

  • return true;

  • }

  • i = (i + 1) & mask;

  • }

  • return false;

  • }

  • /**

  • * 移除此雙端隊(duì)列中最后一次出現(xiàn)的指定元素(當(dāng)從頭部到尾部遍歷雙端隊(duì)列時(shí))。

  • */

  • public boolean removeLastOccurrence(Object o) {

  • if (o == null)

  • return false;

  • int mask = elements.length - 1;

  • int i = (tail - 1) & mask;

  • E x;

  • while ( (x = elements[i]) != null) {

  • if (o.equals(x)) {

  • delete(i);

  • return true;

  • }

  • i = (i - 1) & mask;

  • }

  • return false;

  • }

  • // *** 隊(duì)列方法(Queue methods) ***

  • /**

  • * add方法,添加到隊(duì)列末端

  • */

  • public boolean add(E e) {

  • addLast(e);

  • return true;

  • }

  • /**

  • * 同上

  • */

  • public boolean offer(E e) {

  • return offerLast(e);

  • }

  • /**

  • * remove元素,刪除隊(duì)列前端

  • */

  • public E remove() {

  • return removeFirst();

  • }

  • /**

  • * 彈出前端(出對(duì),刪除前端)

  • */

  • public E poll() {

  • return pollFirst();

  • }

  • public E element() {

  • return getFirst();

  • }

  • public E peek() {

  • return peekFirst();

  • }

  • // *** 棧 方法(Stack methods) ***

  • public void push(E e) {

  • addFirst(e);

  • }

  • public E pop() {

  • return removeFirst();

  • }

  • private void checkInvariants() { …… }

  • private boolean delete(int i) { …… }

  • // *** 集合方法(Collection Methods) ***

  • ……

  • // *** Object methods ***

  • ……

  • }

  • 整體來(lái)說(shuō):1個(gè)數(shù)組,2個(gè)index(head 索引和tail索引)。實(shí)現(xiàn)比較簡(jiǎn)單,容易理解。


  • ?

    ?

    2、LinkedList實(shí)現(xiàn)Deque

    ?

    對(duì)于LinkedList本身而言,數(shù)據(jù)結(jié)構(gòu)就更簡(jiǎn)單了,除了一個(gè)size用來(lái)記錄大小外,只有head一個(gè)元素Entry。對(duì)比Map和Queue的其它數(shù)據(jù)結(jié)構(gòu)可以看到這里的Entry有兩個(gè)引用,是雙向的隊(duì)列。

    在示意圖中,LinkedList總是有一個(gè)“傀儡”節(jié)點(diǎn),用來(lái)描述隊(duì)列“頭部”,但是并不表示頭部元素,它是一個(gè)執(zhí)行null的空節(jié)點(diǎn)。

    隊(duì)列一開(kāi)始只有head一個(gè)空元素,然后從尾部加入E1(add/addLast),head和E1之間建立雙向鏈接。然后繼續(xù)從尾部加入E2,E2就在head和E1之間建立雙向鏈接。最后從隊(duì)列的頭部加入E3(push/addFirst),于是E3就在E1和head之間鏈接雙向鏈接。

    雙向鏈表的數(shù)據(jù)結(jié)構(gòu)比較簡(jiǎn)單,操作起來(lái)也比較容易,從事從“傀儡”節(jié)點(diǎn)開(kāi)始,“傀儡”節(jié)點(diǎn)的下一個(gè)元素就是隊(duì)列的頭部,前一個(gè)元素是隊(duì)列的尾部,換句話說(shuō),“傀儡”節(jié)點(diǎn)在頭部和尾部之間建立了一個(gè)通道,是整個(gè)隊(duì)列形成一個(gè)循環(huán),這樣就可以從任意一個(gè)節(jié)點(diǎn)的任意一個(gè)方向能遍歷完整的隊(duì)列。

    同樣LinkedList也是一個(gè)沒(méi)有容量限制的隊(duì)列,因此入隊(duì)列(不管是從頭部還是尾部)總能成功。

    ?

    3、小結(jié)?

    ?

    上面描述的ArrayDeque和LinkedList是兩種不同方式的實(shí)現(xiàn),通常在遍歷和節(jié)省內(nèi)存上ArrayDeque更高效(索引更快,另外不需要Entry對(duì)象),但是在隊(duì)列擴(kuò)容下LinkedList更靈活,因?yàn)椴恍枰獜?fù)制原始的隊(duì)列,某些情況下可能更高效。

    同樣需要注意的上述兩個(gè)實(shí)現(xiàn)都不是線程安全的,因此只適合在單線程環(huán)境下使用,下面章節(jié)要介紹的LinkedBlockingDeque就是線程安全的可阻塞的Deque。事實(shí)上也應(yīng)該是功能最強(qiáng)大的Queue實(shí)現(xiàn),當(dāng)然了實(shí)現(xiàn)起來(lái)也許會(huì)復(fù)雜一點(diǎn)。

    ?

    二、雙向并發(fā)阻塞隊(duì)列?LinkedBlockingDeque

    ?

    1、LinkedBlockingDeque數(shù)據(jù)結(jié)構(gòu)

    ?

    雙向并發(fā)阻塞隊(duì)列。所謂雙向是指可以從隊(duì)列的頭和尾同時(shí)操作,并發(fā)只是線程安全的實(shí)現(xiàn),阻塞允許在入隊(duì)出隊(duì)不滿足條件時(shí)掛起線程,這里說(shuō)的隊(duì)列是指支持FIFO/FILO實(shí)現(xiàn)的鏈表。

    ?

    首先看下LinkedBlockingDeque的數(shù)據(jù)結(jié)構(gòu)。通常情況下從數(shù)據(jù)結(jié)構(gòu)上就能看出這種實(shí)現(xiàn)的優(yōu)缺點(diǎn),這樣就知道如何更好的使用工具了。

    從數(shù)據(jù)結(jié)構(gòu)和功能需求上可以得到以下結(jié)論:

  • 要想支持阻塞功能,隊(duì)列的容量一定是固定的,否則無(wú)法在入隊(duì)的時(shí)候掛起線程。也就是capacity是final類型的。
  • 既然是雙向鏈表,每一個(gè)結(jié)點(diǎn)就需要前后兩個(gè)引用,這樣才能將所有元素串聯(lián)起來(lái),支持雙向遍歷。也即需要prev/next兩個(gè)引用。
  • 雙向鏈表需要頭尾同時(shí)操作,所以需要first/last兩個(gè)節(jié)點(diǎn),當(dāng)然可以參考LinkedList那樣采用一個(gè)節(jié)點(diǎn)的雙向來(lái)完成,那樣實(shí)現(xiàn)起來(lái)就稍微麻煩點(diǎn)。
  • 既然要支持阻塞功能,就需要鎖和條件變量來(lái)掛起線程。這里使用一個(gè)鎖兩個(gè)條件變量來(lái)完成此功能。
  • ?

    2、LinkedBlockingDeque源碼分析

    ?

    ?

  • public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingDeque<E>, java.io.Serializable {

  • /** 包含前驅(qū)和后繼節(jié)點(diǎn)的雙向鏈?zhǔn)浇Y(jié)構(gòu) */

  • static final class Node<E> {

  • E item;

  • Node<E> prev;

  • Node<E> next;

  • Node(E x, Node<E> p, Node<E> n) {

  • item = x;

  • prev = p;

  • next = n;

  • }

  • }

  • /** 頭節(jié)點(diǎn) */

  • private transient Node<E> first;

  • /** 尾節(jié)點(diǎn) */

  • private transient Node<E> last;

  • /** 元素個(gè)數(shù)*/

  • private transient int count;

  • /** 隊(duì)列容量 */

  • private final int capacity;

  • /** 鎖 */

  • private final ReentrantLock lock = new ReentrantLock();

  • /** notEmpty條件 */

  • private final Condition notEmpty = lock.newCondition();

  • /** notFull條件 */

  • private final Condition notFull = lock.newCondition();

  • /** 構(gòu)造方法 */

  • public LinkedBlockingDeque() {

  • this(Integer.MAX_VALUE);

  • }

  • public LinkedBlockingDeque(int capacity) {

  • if (capacity <= 0) throw new IllegalArgumentException();

  • this.capacity = capacity;

  • }

  • public LinkedBlockingDeque(Collection<? extends E> c) {

  • this(Integer.MAX_VALUE);

  • for (E e : c)

  • add(e);

  • }

  • ?
  • /**

  • * 添加元素作為新的頭節(jié)點(diǎn)

  • */

  • private boolean linkFirst(E e) {

  • if (count >= capacity)

  • return false;

  • ++count;

  • Node<E> f = first;

  • Node<E> x = new Node<E>(e, null, f);

  • first = x;

  • if (last == null)

  • last = x;

  • else

  • f.prev = x;

  • notEmpty.signal();

  • return true;

  • }

  • /**

  • * 添加尾元素

  • */

  • private boolean linkLast(E e) {

  • if (count >= capacity)

  • return false;

  • ++count;

  • Node<E> l = last;

  • Node<E> x = new Node<E>(e, l, null);

  • last = x;

  • if (first == null)

  • first = x;

  • else

  • l.next = x;

  • notEmpty.signal();

  • return true;

  • }

  • /**

  • * 返回并移除頭節(jié)點(diǎn)

  • */

  • private E unlinkFirst() {

  • Node<E> f = first;

  • if (f == null)

  • return null;

  • Node<E> n = f.next;

  • first = n;

  • if (n == null)

  • last = null;

  • else

  • n.prev = null;

  • --count;

  • notFull.signal();

  • return f.item;

  • }

  • /**

  • * 返回并移除尾節(jié)點(diǎn)

  • */

  • private E unlinkLast() {

  • Node<E> l = last;

  • if (l == null)

  • return null;

  • Node<E> p = l.prev;

  • last = p;

  • if (p == null)

  • first = null;

  • else

  • p.next = null;

  • --count;

  • notFull.signal();

  • return l.item;

  • }

  • /**

  • * 移除節(jié)點(diǎn)x

  • */

  • private void unlink(Node<E> x) {

  • Node<E> p = x.prev;

  • Node<E> n = x.next;

  • if (p == null) {//x是頭的情況

  • if (n == null)

  • first = last = null;

  • else {

  • n.prev = null;

  • first = n;

  • }

  • } else if (n == null) {//x是尾的情況

  • p.next = null;

  • last = p;

  • } else {//x是中間的情況

  • p.next = n;

  • n.prev = p;

  • }

  • --count;

  • notFull.signalAll();

  • }

  • //--------------------------------- BlockingDeque 雙端阻塞隊(duì)列方法實(shí)現(xiàn)

  • public void addFirst(E e) {

  • if (!offerFirst(e))

  • throw new IllegalStateException("Deque full");

  • }

  • public void addLast(E e) {

  • if (!offerLast(e))

  • throw new IllegalStateException("Deque full");

  • }

  • public boolean offerFirst(E e) {

  • if (e == null) throw new NullPointerException();

  • lock.lock();

  • try {

  • return linkFirst(e);

  • } finally {

  • lock.unlock();

  • }

  • }

  • public boolean offerLast(E e) {

  • if (e == null) throw new NullPointerException();

  • lock.lock();

  • try {

  • return linkLast(e);

  • } finally {

  • lock.unlock();

  • }

  • }

  • public void putFirst(E e) throws InterruptedException {

  • if (e == null) throw new NullPointerException();

  • lock.lock();

  • try {

  • while (!linkFirst(e))

  • notFull.await();

  • } finally {

  • lock.unlock();

  • }

  • }

  • public void putLast(E e) throws InterruptedException {

  • if (e == null) throw new NullPointerException();

  • lock.lock();

  • try {

  • while (!linkLast(e))

  • notFull.await();

  • } finally {

  • lock.unlock();

  • }

  • }

  • public boolean offerFirst(E e, long timeout, TimeUnit unit)

  • throws InterruptedException {

  • if (e == null) throw new NullPointerException();

  • long nanos = unit.toNanos(timeout);

  • lock.lockInterruptibly();

  • try {

  • for (;;) {

  • if (linkFirst(e))

  • return true;

  • if (nanos <= 0)

  • return false;

  • nanos = notFull.awaitNanos(nanos);

  • }

  • } finally {

  • lock.unlock();

  • }

  • }

  • public boolean offerLast(E e, long timeout, TimeUnit unit)

  • throws InterruptedException {

  • if (e == null) throw new NullPointerException();

  • long nanos = unit.toNanos(timeout);

  • lock.lockInterruptibly();

  • try {

  • for (;;) {

  • if (linkLast(e))

  • return true;

  • if (nanos <= 0)

  • return false;

  • nanos = notFull.awaitNanos(nanos);

  • }

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E removeFirst() {

  • E x = pollFirst();

  • if (x == null) throw new NoSuchElementException();

  • return x;

  • }

  • public E removeLast() {

  • E x = pollLast();

  • if (x == null) throw new NoSuchElementException();

  • return x;

  • }

  • public E pollFirst() {

  • lock.lock();

  • try {

  • return unlinkFirst();

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E pollLast() {

  • lock.lock();

  • try {

  • return unlinkLast();

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E takeFirst() throws InterruptedException {

  • lock.lock();

  • try {

  • E x;

  • while ( (x = unlinkFirst()) == null)

  • notEmpty.await();

  • return x;

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E takeLast() throws InterruptedException {

  • lock.lock();

  • try {

  • E x;

  • while ( (x = unlinkLast()) == null)

  • notEmpty.await();

  • return x;

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E pollFirst(long timeout, TimeUnit unit)

  • throws InterruptedException {

  • long nanos = unit.toNanos(timeout);

  • lock.lockInterruptibly();

  • try {

  • for (;;) {

  • E x = unlinkFirst();

  • if (x != null)

  • return x;

  • if (nanos <= 0)

  • return null;

  • nanos = notEmpty.awaitNanos(nanos);

  • }

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E pollLast(long timeout, TimeUnit unit)

  • throws InterruptedException {

  • long nanos = unit.toNanos(timeout);

  • lock.lockInterruptibly();

  • try {

  • for (;;) {

  • E x = unlinkLast();

  • if (x != null)

  • return x;

  • if (nanos <= 0)

  • return null;

  • nanos = notEmpty.awaitNanos(nanos);

  • }

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E getFirst() {

  • E x = peekFirst();

  • if (x == null) throw new NoSuchElementException();

  • return x;

  • }

  • public E getLast() {

  • E x = peekLast();

  • if (x == null) throw new NoSuchElementException();

  • return x;

  • }

  • public E peekFirst() {

  • lock.lock();

  • try {

  • return (first == null) ? null : first.item;

  • } finally {

  • lock.unlock();

  • }

  • }

  • public E peekLast() {

  • lock.lock();

  • try {

  • return (last == null) ? null : last.item;

  • } finally {

  • lock.unlock();

  • }

  • }

  • public boolean removeFirstOccurrence(Object o) {

  • if (o == null) return false;

  • lock.lock();

  • try {

  • for (Node<E> p = first; p != null; p = p.next) {

  • if (o.equals(p.item)) {

  • unlink(p);

  • return true;

  • }

  • }

  • return false;

  • } finally {

  • lock.unlock();

  • }

  • }

  • public boolean removeLastOccurrence(Object o) {

  • if (o == null) return false;

  • lock.lock();

  • try {

  • for (Node<E> p = last; p != null; p = p.prev) {

  • if (o.equals(p.item)) {

  • unlink(p);

  • return true;

  • }

  • }

  • return false;

  • } finally {

  • lock.unlock();

  • }

  • }

  • //---------------------------------- BlockingQueue阻塞隊(duì)列 方法實(shí)現(xiàn)

  • public boolean add(E e) {

  • addLast(e);

  • return true;

  • }

  • public boolean offer(E e) {

  • return offerLast(e);

  • }

  • public void put(E e) throws InterruptedException {

  • putLast(e);

  • }

  • public boolean offer(E e, long timeout, TimeUnit unit)

  • throws InterruptedException {

  • return offerLast(e, timeout, unit);

  • }

  • public E remove() {

  • return removeFirst();

  • }

  • public E poll() {

  • return pollFirst();

  • }

  • public E take() throws InterruptedException {

  • return takeFirst();

  • }

  • public E poll(long timeout, TimeUnit unit) throws InterruptedException {

  • return pollFirst(timeout, unit);

  • }

  • public E element() {

  • return getFirst();

  • }

  • public E peek() {

  • return peekFirst();

  • }

  • //------------------------------------------- Stack 方法實(shí)現(xiàn)

  • public void push(E e) {

  • addFirst(e);

  • }

  • public E pop() {

  • return removeFirst();

  • }

  • //------------------------------------------- Collection 方法實(shí)現(xiàn)

  • public boolean remove(Object o) {

  • return removeFirstOccurrence(o);

  • }

  • public int size() {

  • lock.lock();

  • try {

  • return count;

  • } finally {

  • lock.unlock();

  • }

  • }

  • public boolean contains(Object o) {

  • if (o == null) return false;

  • 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();

  • }

  • }

  • boolean removeNode(Node<E> e) {

  • lock.lock();

  • try {

  • for (Node<E> p = first; p != null; p = p.next) {

  • if (p == e) {

  • unlink(p);

  • return true;

  • }

  • }

  • return false;

  • } finally {

  • lock.unlock();

  • }

  • }

  • ……

  • }


  • ?

    3、LinkedBlockingDeque的優(yōu)缺點(diǎn)

    ?

    有了上面的結(jié)論再來(lái)研究LinkedBlockingDeque的優(yōu)缺點(diǎn)。

    優(yōu)點(diǎn)當(dāng)然是功能足夠強(qiáng)大,同時(shí)由于采用一個(gè)獨(dú)占鎖,因此實(shí)現(xiàn)起來(lái)也比較簡(jiǎn)單。所有對(duì)隊(duì)列的操作都加鎖就可以完成。同時(shí)獨(dú)占鎖也能夠很好的支持雙向阻塞的特性。

    凡事有利必有弊。缺點(diǎn)就是由于獨(dú)占鎖,所以不能同時(shí)進(jìn)行兩個(gè)操作,這樣性能上就大打折扣。從性能的角度講LinkedBlockingDeque要比LinkedBlockingQueue要低很多,比CocurrentLinkedQueue就低更多了,這在高并發(fā)情況下就比較明顯了。

    前面分析足夠多的Queue實(shí)現(xiàn)后,LinkedBlockingDeque的原理和實(shí)現(xiàn)就不值得一提了,無(wú)非是在獨(dú)占鎖下對(duì)一個(gè)鏈表的普通操作。

    ?

    4、LinkedBlockingDeque的序列化、反序列化

    ?

    有趣的是此類支持序列化,但是Node并不支持序列化,因此fist/last就不能序列化,那么如何完成序列化/反序列化過(guò)程呢?

    清單4 LinkedBlockingDeque的序列化、反序列化

    ?

  • private void writeObject(java.io.ObjectOutputStream s)

  • throws java.io.IOException {

  • lock.lock();

  • try {

  • // Write out capacity and any hidden stuff

  • s.defaultWriteObject();

  • // Write out all elements in the proper order.

  • for (Node<E> p = first; p != null; p = p.next)

  • s.writeObject(p.item);

  • // Use trailing null as sentinel

  • s.writeObject(null);

  • } finally {

  • lock.unlock();

  • }

  • }

  • ?
  • private void readObject(java.io.ObjectInputStream s)

  • throws java.io.IOException, ClassNotFoundException {

  • s.defaultReadObject();

  • count = 0;

  • first = null;

  • last = null;

  • // Read in all elements and place in queue

  • for (;;) {

  • E item = (E)s.readObject();

  • if (item == null)

  • break;

  • add(item);

  • }

  • }

  • ?
  • ?

  • ?

    清單4 描述的是LinkedBlockingDeque序列化/反序列化的過(guò)程。序列化時(shí)將真正的元素寫入輸出流,最后還寫入了一個(gè)null。讀取的時(shí)候?qū)⑺袑?duì)象列表讀出來(lái),如果讀取到一個(gè)null就表示結(jié)束。這就是為什么寫入的時(shí)候?qū)懭胍粋€(gè)null的原因,因?yàn)闆](méi)有將count寫入流,所以就靠null來(lái)表示結(jié)束,省一個(gè)整數(shù)空間。

    ?

    參考內(nèi)容來(lái)源:

    ?

    集合框架 Queue篇(1)---ArrayDeque
    http://hi.baidu.com/yao1111yao/item/1a1346f65a50d9c8521c266d
    集合框架 Queue篇(7)---LinkedBlockingDeque
    http://hi.baidu.com/yao1111yao/item/b1649cff2cf60be91a111f6d
    深入淺出 Java Concurrency (24): 并發(fā)容器 part 9 雙向隊(duì)列集合 Deque
    http://www.blogjava.net/xylz/archive/2010/08/12/328587.html
    深入淺出 Java Concurrency (25): 并發(fā)容器 part 10 雙向并發(fā)阻塞隊(duì)列 BlockingDeque
    http://www.blogjava.net/xylz/archive/2010/08/18/329227.html

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的Java多线程(六)之Deque与LinkedBlockingDeque深入分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。