skywang12345

导航

 

 

概要

本章介绍JUC包中的LinkedBlockingDeque。内容包括:
LinkedBlockingDeque介绍
LinkedBlockingDeque原理和数据结构
LinkedBlockingDeque函数列表
LinkedBlockingDeque源码分析(JDK1.7.0_40版本)
LinkedBlockingDeque示例

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3503480.html

 

LinkedBlockingDeque介绍

LinkedBlockingDeque是双向链表实现的双向并发阻塞队列。该阻塞队列同时支持FIFO和FILO两种操作方式,即可以从队列的头和尾同时操作(插入/删除);并且,该阻塞队列是支持线程安全。

此外,LinkedBlockingDeque还是可选容量的(防止过度膨胀),即可以指定队列的容量。如果不指定,默认容量大小等于Integer.MAX_VALUE。

 

LinkedBlockingDeque原理和数据结构

LinkedBlockingDeque的数据结构,如下图所示:

说明:
1. LinkedBlockingDeque继承于AbstractQueue,它本质上是一个支持FIFO和FILO的双向的队列。
2. LinkedBlockingDeque实现了BlockingDeque接口,它支持多线程并发。当多线程竞争同一个资源时,某线程获取到该资源之后,其它线程需要阻塞等待。
3. LinkedBlockingDeque是通过双向链表实现的。
3.1 first是双向链表的表头。
3.2 last是双向链表的表尾。
3.3 count是LinkedBlockingDeque的实际大小,即双向链表中当前节点个数。
3.4 capacity是LinkedBlockingDeque的容量,它是在创建LinkedBlockingDeque时指定的。
3.5 lock是控制对LinkedBlockingDeque的互斥锁,当多个线程竞争同时访问LinkedBlockingDeque时,某线程获取到了互斥锁lock,其它线程则需要阻塞等待,直到该线程释放lock,其它线程才有机会获取lock从而获取cpu执行权。
3.6 notEmpty和notFull分别是“非空条件”和“未满条件”。通过它们能够更加细腻进行并发控制。

     -- 若某线程(线程A)要取出数据时,队列正好为空,则该线程会执行notEmpty.await()进行等待;当其它某个线程(线程B)向队列中插入了数据之后,会调用notEmpty.signal()唤醒“notEmpty上的等待线程”。此时,线程A会被唤醒从而得以继续运行。 此外,线程A在执行取操作前,会获取takeLock,在取操作执行完毕再释放takeLock。
     -- 若某线程(线程H)要插入数据时,队列已满,则该线程会它执行notFull.await()进行等待;当其它某个线程(线程I)取出数据之后,会调用notFull.signal()唤醒“notFull上的等待线程”。此时,线程H就会被唤醒从而得以继续运行。 此外,线程H在执行插入操作前,会获取putLock,在插入操作执行完毕才释放putLock。

关于ReentrantLock 和 Condition等更多的内容,可以参考:
    (01) Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
    (02) Java多线程系列--“JUC锁”03之 公平锁(一)
    (03) Java多线程系列--“JUC锁”04之 公平锁(二)
    (04) Java多线程系列--“JUC锁”05之 非公平锁
    (05) Java多线程系列--“JUC锁”06之 Condition条件

 

LinkedBlockingDeque函数列表

// 创建一个容量为 Integer.MAX_VALUE 的 LinkedBlockingDeque。
LinkedBlockingDeque()
// 创建一个容量为 Integer.MAX_VALUE 的 LinkedBlockingDeque,最初包含给定 collection 的元素,以该 collection 迭代器的遍历顺序添加。
LinkedBlockingDeque(Collection<? extends E> c)
// 创建一个具有给定(固定)容量的 LinkedBlockingDeque。
LinkedBlockingDeque(int capacity)

// 在不违反容量限制的情况下,将指定的元素插入此双端队列的末尾。
boolean add(E e)
// 如果立即可行且不违反容量限制,则将指定的元素插入此双端队列的开头;如果当前没有空间可用,则抛出 IllegalStateException。
void addFirst(E e)
// 如果立即可行且不违反容量限制,则将指定的元素插入此双端队列的末尾;如果当前没有空间可用,则抛出 IllegalStateException。
void addLast(E e)
// 以原子方式 (atomically) 从此双端队列移除所有元素。
void clear()
// 如果此双端队列包含指定的元素,则返回 true。
boolean contains(Object o)
// 返回在此双端队列的元素上以逆向连续顺序进行迭代的迭代器。
Iterator<E> descendingIterator()
// 移除此队列中所有可用的元素,并将它们添加到给定 collection 中。
int drainTo(Collection<? super E> c)
// 最多从此队列中移除给定数量的可用元素,并将这些元素添加到给定 collection 中。
int drainTo(Collection<? super E> c, int maxElements)
// 获取但不移除此双端队列表示的队列的头部。
E element()
// 获取,但不移除此双端队列的第一个元素。
E getFirst()
// 获取,但不移除此双端队列的最后一个元素。
E getLast()
// 返回在此双端队列元素上以恰当顺序进行迭代的迭代器。
Iterator<E> iterator()
// 如果立即可行且不违反容量限制,则将指定的元素插入此双端队列表示的队列中(即此双端队列的尾部),并在成功时返回 true;如果当前没有空间可用,则返回 false。
boolean offer(E e)
// 将指定的元素插入此双端队列表示的队列中(即此双端队列的尾部),必要时将在指定的等待时间内一直等待可用空间。
boolean offer(E e, long timeout, TimeUnit unit)
// 如果立即可行且不违反容量限制,则将指定的元素插入此双端队列的开头,并在成功时返回 true;如果当前没有空间可用,则返回 false。
boolean offerFirst(E e)
// 将指定的元素插入此双端队列的开头,必要时将在指定的等待时间内等待可用空间。
boolean offerFirst(E e, long timeout, TimeUnit unit)
// 如果立即可行且不违反容量限制,则将指定的元素插入此双端队列的末尾,并在成功时返回 true;如果当前没有空间可用,则返回 false。
boolean offerLast(E e)
// 将指定的元素插入此双端队列的末尾,必要时将在指定的等待时间内等待可用空间。
boolean offerLast(E e, long timeout, TimeUnit unit)
// 获取但不移除此双端队列表示的队列的头部(即此双端队列的第一个元素);如果此双端队列为空,则返回 null。
E peek()
// 获取,但不移除此双端队列的第一个元素;如果此双端队列为空,则返回 null。
E peekFirst()
// 获取,但不移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null。
E peekLast()
// 获取并移除此双端队列表示的队列的头部(即此双端队列的第一个元素);如果此双端队列为空,则返回 null。
E poll()
// 获取并移除此双端队列表示的队列的头部(即此双端队列的第一个元素),如有必要将在指定的等待时间内等待可用元素。
E poll(long timeout, TimeUnit unit)
// 获取并移除此双端队列的第一个元素;如果此双端队列为空,则返回 null。
E pollFirst()
// 获取并移除此双端队列的第一个元素,必要时将在指定的等待时间等待可用元素。
E pollFirst(long timeout, TimeUnit unit)
// 获取并移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null。
E pollLast()
// 获取并移除此双端队列的最后一个元素,必要时将在指定的等待时间内等待可用元素。
E pollLast(long timeout, TimeUnit unit)
// 从此双端队列所表示的堆栈中弹出一个元素。
E pop()
// 将元素推入此双端队列表示的栈。
void push(E e)
// 将指定的元素插入此双端队列表示的队列中(即此双端队列的尾部),必要时将一直等待可用空间。
void put(E e)
// 将指定的元素插入此双端队列的开头,必要时将一直等待可用空间。
void putFirst(E e)
// 将指定的元素插入此双端队列的末尾,必要时将一直等待可用空间。
void putLast(E e)
// 返回理想情况下(没有内存和资源约束)此双端队列可不受阻塞地接受的额外元素数。
int remainingCapacity()
// 获取并移除此双端队列表示的队列的头部。
E remove()
// 从此双端队列移除第一次出现的指定元素。
boolean remove(Object o)
// 获取并移除此双端队列第一个元素。
E removeFirst()
// 从此双端队列移除第一次出现的指定元素。
boolean removeFirstOccurrence(Object o)
// 获取并移除此双端队列的最后一个元素。
E removeLast()
// 从此双端队列移除最后一次出现的指定元素。
boolean removeLastOccurrence(Object o)
// 返回此双端队列中的元素数。
int size()
// 获取并移除此双端队列表示的队列的头部(即此双端队列的第一个元素),必要时将一直等待可用元素。
E take()
// 获取并移除此双端队列的第一个元素,必要时将一直等待可用元素。
E takeFirst()
// 获取并移除此双端队列的最后一个元素,必要时将一直等待可用元素。
E takeLast()
// 返回以恰当顺序(从第一个元素到最后一个元素)包含此双端队列所有元素的数组。
Object[] toArray()
// 返回以恰当顺序包含此双端队列所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。
<T> T[] toArray(T[] a)
// 返回此 collection 的字符串表示形式。
String toString()

 

LinkedBlockingDeque源码分析(JDK1.7.0_40版本)

LinkedBlockingDeque.java的完整源码如下:

   1 /*
   2  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
   3  *
   4  *
   5  *
   6  *
   7  *
   8  *
   9  *
  10  *
  11  *
  12  *
  13  *
  14  *
  15  *
  16  *
  17  *
  18  *
  19  *
  20  *
  21  *
  22  *
  23  */
  24 
  25 /*
  26  *
  27  *
  28  *
  29  *
  30  *
  31  * Written by Doug Lea with assistance from members of JCP JSR-166
  32  * Expert Group and released to the public domain, as explained at
  33  * http://creativecommons.org/publicdomain/zero/1.0/
  34  */
  35 
  36 package java.util.concurrent;
  37 
  38 import java.util.AbstractQueue;
  39 import java.util.Collection;
  40 import java.util.Iterator;
  41 import java.util.NoSuchElementException;
  42 import java.util.concurrent.locks.Condition;
  43 import java.util.concurrent.locks.ReentrantLock;
  44 
  45 /**
  46  * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
  47  * linked nodes.
  48  *
  49  * <p> The optional capacity bound constructor argument serves as a
  50  * way to prevent excessive expansion. The capacity, if unspecified,
  51  * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
  52  * dynamically created upon each insertion unless this would bring the
  53  * deque above capacity.
  54  *
  55  * <p>Most operations run in constant time (ignoring time spent
  56  * blocking).  Exceptions include {@link #remove(Object) remove},
  57  * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link
  58  * #removeLastOccurrence removeLastOccurrence}, {@link #contains
  59  * contains}, {@link #iterator iterator.remove()}, and the bulk
  60  * operations, all of which run in linear time.
  61  *
  62  * <p>This class and its iterator implement all of the
  63  * <em>optional</em> methods of the {@link Collection} and {@link
  64  * Iterator} interfaces.
  65  *
  66  * <p>This class is a member of the
  67  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  68  * Java Collections Framework</a>.
  69  *
  70  * @since 1.6
  71  * @author  Doug Lea
  72  * @param <E> the type of elements held in this collection
  73  */
  74 public class LinkedBlockingDeque<E>
  75     extends AbstractQueue<E>
  76     implements BlockingDeque<E>,  java.io.Serializable {
  77 
  78     /*
  79      * Implemented as a simple doubly-linked list protected by a
  80      * single lock and using conditions to manage blocking.
  81      *
  82      * To implement weakly consistent iterators, it appears we need to
  83      * keep all Nodes GC-reachable from a predecessor dequeued Node.
  84      * That would cause two problems:
  85      * - allow a rogue Iterator to cause unbounded memory retention
  86      * - cause cross-generational linking of old Nodes to new Nodes if
  87      *   a Node was tenured while live, which generational GCs have a
  88      *   hard time dealing with, causing repeated major collections.
  89      * However, only non-deleted Nodes need to be reachable from
  90      * dequeued Nodes, and reachability does not necessarily have to
  91      * be of the kind understood by the GC.  We use the trick of
  92      * linking a Node that has just been dequeued to itself.  Such a
  93      * self-link implicitly means to jump to "first" (for next links)
  94      * or "last" (for prev links).
  95      */
  96 
  97     /*
  98      * We have "diamond" multiple interface/abstract class inheritance
  99      * here, and that introduces ambiguities. Often we want the
 100      * BlockingDeque javadoc combined with the AbstractQueue
 101      * implementation, so a lot of method specs are duplicated here.
 102      */
 103 
 104     private static final long serialVersionUID = -387911632671998426L;
 105 
 106     /** Doubly-linked list node class */
 107     static final class Node<E> {
 108         /**
 109          * The item, or null if this node has been removed.
 110          */
 111         E item;
 112 
 113         /**
 114          * One of:
 115          * - the real predecessor Node
 116          * - this Node, meaning the predecessor is tail
 117          * - null, meaning there is no predecessor
 118          */
 119         Node<E> prev;
 120 
 121         /**
 122          * One of:
 123          * - the real successor Node
 124          * - this Node, meaning the successor is head
 125          * - null, meaning there is no successor
 126          */
 127         Node<E> next;
 128 
 129         Node(E x) {
 130             item = x;
 131         }
 132     }
 133 
 134     /**
 135      * Pointer to first node.
 136      * Invariant: (first == null && last == null) ||
 137      *            (first.prev == null && first.item != null)
 138      */
 139     transient Node<E> first;
 140 
 141     /**
 142      * Pointer to last node.
 143      * Invariant: (first == null && last == null) ||
 144      *            (last.next == null && last.item != null)
 145      */
 146     transient Node<E> last;
 147 
 148     /** Number of items in the deque */
 149     private transient int count;
 150 
 151     /** Maximum number of items in the deque */
 152     private final int capacity;
 153 
 154     /** Main lock guarding all access */
 155     final ReentrantLock lock = new ReentrantLock();
 156 
 157     /** Condition for waiting takes */
 158     private final Condition notEmpty = lock.newCondition();
 159 
 160     /** Condition for waiting puts */
 161     private final Condition notFull = lock.newCondition();
 162 
 163     /**
 164      * Creates a {@code LinkedBlockingDeque} with a capacity of
 165      * {@link Integer#MAX_VALUE}.
 166      */
 167     public LinkedBlockingDeque() {
 168         this(Integer.MAX_VALUE);
 169     }
 170 
 171     /**
 172      * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
 173      *
 174      * @param capacity the capacity of this deque
 175      * @throws IllegalArgumentException if {@code capacity} is less than 1
 176      */
 177     public LinkedBlockingDeque(int capacity) {
 178         if (capacity <= 0) throw new IllegalArgumentException();
 179         this.capacity = capacity;
 180     }
 181 
 182     /**
 183      * Creates a {@code LinkedBlockingDeque} with a capacity of
 184      * {@link Integer#MAX_VALUE}, initially containing the elements of
 185      * the given collection, added in traversal order of the
 186      * collection's iterator.
 187      *
 188      * @param c the collection of elements to initially contain
 189      * @throws NullPointerException if the specified collection or any
 190      *         of its elements are null
 191      */
 192     public LinkedBlockingDeque(Collection<? extends E> c) {
 193         this(Integer.MAX_VALUE);
 194         final ReentrantLock lock = this.lock;
 195         lock.lock(); // Never contended, but necessary for visibility
 196         try {
 197             for (E e : c) {
 198                 if (e == null)
 199                     throw new NullPointerException();
 200                 if (!linkLast(new Node<E>(e)))
 201                     throw new IllegalStateException("Deque full");
 202             }
 203         } finally {
 204             lock.unlock();
 205         }
 206     }
 207 
 208 
 209     // Basic linking and unlinking operations, called only while holding lock
 210 
 211     /**
 212      * Links node as first element, or returns false if full.
 213      */
 214     private boolean linkFirst(Node<E> node) {
 215         // assert lock.isHeldByCurrentThread();
 216         if (count >= capacity)
 217             return false;
 218         Node<E> f = first;
 219         node.next = f;
 220         first = node;
 221         if (last == null)
 222             last = node;
 223         else
 224             f.prev = node;
 225         ++count;
 226         notEmpty.signal();
 227         return true;
 228     }
 229 
 230     /**
 231      * Links node as last element, or returns false if full.
 232      */
 233     private boolean linkLast(Node<E> node) {
 234         // assert lock.isHeldByCurrentThread();
 235         if (count >= capacity)
 236             return false;
 237         Node<E> l = last;
 238         node.prev = l;
 239         last = node;
 240         if (first == null)
 241             first = node;
 242         else
 243             l.next = node;
 244         ++count;
 245         notEmpty.signal();
 246         return true;
 247     }
 248 
 249     /**
 250      * Removes and returns first element, or null if empty.
 251      */
 252     private E unlinkFirst() {
 253         // assert lock.isHeldByCurrentThread();
 254         Node<E> f = first;
 255         if (f == null)
 256             return null;
 257         Node<E> n = f.next;
 258         E item = f.item;
 259         f.item = null;
 260         f.next = f; // help GC
 261         first = n;
 262         if (n == null)
 263             last = null;
 264         else
 265             n.prev = null;
 266         --count;
 267         notFull.signal();
 268         return item;
 269     }
 270 
 271     /**
 272      * Removes and returns last element, or null if empty.
 273      */
 274     private E unlinkLast() {
 275         // assert lock.isHeldByCurrentThread();
 276         Node<E> l = last;
 277         if (l == null)
 278             return null;
 279         Node<E> p = l.prev;
 280         E item = l.item;
 281         l.item = null;
 282         l.prev = l; // help GC
 283         last = p;
 284         if (p == null)
 285             first = null;
 286         else
 287             p.next = null;
 288         --count;
 289         notFull.signal();
 290         return item;
 291     }
 292 
 293     /**
 294      * Unlinks x.
 295      */
 296     void unlink(Node<E> x) {
 297         // assert lock.isHeldByCurrentThread();
 298         Node<E> p = x.prev;
 299         Node<E> n = x.next;
 300         if (p == null) {
 301             unlinkFirst();
 302         } else if (n == null) {
 303             unlinkLast();
 304         } else {
 305             p.next = n;
 306             n.prev = p;
 307             x.item = null;
 308             // Don't mess with x's links.  They may still be in use by
 309             // an iterator.
 310             --count;
 311             notFull.signal();
 312         }
 313     }
 314 
 315     // BlockingDeque methods
 316 
 317     /**
 318      * @throws IllegalStateException {@inheritDoc}
 319      * @throws NullPointerException  {@inheritDoc}
 320      */
 321     public void addFirst(E e) {
 322         if (!offerFirst(e))
 323             throw new IllegalStateException("Deque full");
 324     }
 325 
 326     /**
 327      * @throws IllegalStateException {@inheritDoc}
 328      * @throws NullPointerException  {@inheritDoc}
 329      */
 330     public void addLast(E e) {
 331         if (!offerLast(e))
 332             throw new IllegalStateException("Deque full");
 333     }
 334 
 335     /**
 336      * @throws NullPointerException {@inheritDoc}
 337      */
 338     public boolean offerFirst(E e) {
 339         if (e == null) throw new NullPointerException();
 340         Node<E> node = new Node<E>(e);
 341         final ReentrantLock lock = this.lock;
 342         lock.lock();
 343         try {
 344             return linkFirst(node);
 345         } finally {
 346             lock.unlock();
 347         }
 348     }
 349 
 350     /**
 351      * @throws NullPointerException {@inheritDoc}
 352      */
 353     public boolean offerLast(E e) {
 354         if (e == null) throw new NullPointerException();
 355         Node<E> node = new Node<E>(e);
 356         final ReentrantLock lock = this.lock;
 357         lock.lock();
 358         try {
 359             return linkLast(node);
 360         } finally {
 361             lock.unlock();
 362         }
 363     }
 364 
 365     /**
 366      * @throws NullPointerException {@inheritDoc}
 367      * @throws InterruptedException {@inheritDoc}
 368      */
 369     public void putFirst(E e) throws InterruptedException {
 370         if (e == null) throw new NullPointerException();
 371         Node<E> node = new Node<E>(e);
 372         final ReentrantLock lock = this.lock;
 373         lock.lock();
 374         try {
 375             while (!linkFirst(node))
 376                 notFull.await();
 377         } finally {
 378             lock.unlock();
 379         }
 380     }
 381 
 382     /**
 383      * @throws NullPointerException {@inheritDoc}
 384      * @throws InterruptedException {@inheritDoc}
 385      */
 386     public void putLast(E e) throws InterruptedException {
 387         if (e == null) throw new NullPointerException();
 388         Node<E> node = new Node<E>(e);
 389         final ReentrantLock lock = this.lock;
 390         lock.lock();
 391         try {
 392             while (!linkLast(node))
 393                 notFull.await();
 394         } finally {
 395             lock.unlock();
 396         }
 397     }
 398 
 399     /**
 400      * @throws NullPointerException {@inheritDoc}
 401      * @throws InterruptedException {@inheritDoc}
 402      */
 403     public boolean offerFirst(E e, long timeout, TimeUnit unit)
 404         throws InterruptedException {
 405         if (e == null) throw new NullPointerException();
 406         Node<E> node = new Node<E>(e);
 407         long nanos = unit.toNanos(timeout);
 408         final ReentrantLock lock = this.lock;
 409         lock.lockInterruptibly();
 410         try {
 411             while (!linkFirst(node)) {
 412                 if (nanos <= 0)
 413                     return false;
 414                 nanos = notFull.awaitNanos(nanos);
 415             }
 416             return true;
 417         } finally {
 418             lock.unlock();
 419         }
 420     }
 421 
 422     /**
 423      * @throws NullPointerException {@inheritDoc}
 424      * @throws InterruptedException {@inheritDoc}
 425      */
 426     public boolean offerLast(E e, long timeout, TimeUnit unit)
 427         throws InterruptedException {
 428         if (e == null) throw new NullPointerException();
 429         Node<E> node = new Node<E>(e);
 430         long nanos = unit.toNanos(timeout);
 431         final ReentrantLock lock = this.lock;
 432         lock.lockInterruptibly();
 433         try {
 434             while (!linkLast(node)) {
 435                 if (nanos <= 0)
 436                     return false;
 437                 nanos = notFull.awaitNanos(nanos);
 438             }
 439             return true;
 440         } finally {
 441             lock.unlock();
 442         }
 443     }
 444 
 445     /**
 446      * @throws NoSuchElementException {@inheritDoc}
 447      */
 448     public E removeFirst() {
 449         E x = pollFirst();
 450         if (x == null) throw new NoSuchElementException();
 451         return x;
 452     }
 453 
 454     /**
 455      * @throws NoSuchElementException {@inheritDoc}
 456      */
 457     public E removeLast() {
 458         E x = pollLast();
 459         if (x == null) throw new NoSuchElementException();
 460         return x;
 461     }
 462 
 463     public E pollFirst() {
 464         final ReentrantLock lock = this.lock;
 465         lock.lock();
 466         try {
 467             return unlinkFirst();
 468         } finally {
 469             lock.unlock();
 470         }
 471     }
 472 
 473     public E pollLast() {
 474         final ReentrantLock lock = this.lock;
 475         lock.lock();
 476         try {
 477             return unlinkLast();
 478         } finally {
 479             lock.unlock();
 480         }
 481     }
 482 
 483     public E takeFirst() throws InterruptedException {
 484         final ReentrantLock lock = this.lock;
 485         lock.lock();
 486         try {
 487             E x;
 488             while ( (x = unlinkFirst()) == null)
 489                 notEmpty.await();
 490             return x;
 491         } finally {
 492             lock.unlock();
 493         }
 494     }
 495 
 496     public E takeLast() throws InterruptedException {
 497         final ReentrantLock lock = this.lock;
 498         lock.lock();
 499         try {
 500             E x;
 501             while ( (x = unlinkLast()) == null)
 502                 notEmpty.await();
 503             return x;
 504         } finally {
 505             lock.unlock();
 506         }
 507     }
 508 
 509     public E pollFirst(long timeout, TimeUnit unit)
 510         throws InterruptedException {
 511         long nanos = unit.toNanos(timeout);
 512         final ReentrantLock lock = this.lock;
 513         lock.lockInterruptibly();
 514         try {
 515             E x;
 516             while ( (x = unlinkFirst()) == null) {
 517                 if (nanos <= 0)
 518                     return null;
 519                 nanos = notEmpty.awaitNanos(nanos);
 520             }
 521             return x;
 522         } finally {
 523             lock.unlock();
 524         }
 525     }
 526 
 527     public E pollLast(long timeout, TimeUnit unit)
 528         throws InterruptedException {
 529         long nanos = unit.toNanos(timeout);
 530         final ReentrantLock lock = this.lock;
 531         lock.lockInterruptibly();
 532         try {
 533             E x;
 534             while ( (x = unlinkLast()) == null) {
 535                 if (nanos <= 0)
 536                     return null;
 537                 nanos = notEmpty.awaitNanos(nanos);
 538             }
 539             return x;
 540         } finally {
 541             lock.unlock();
 542         }
 543     }
 544 
 545     /**
 546      * @throws NoSuchElementException {@inheritDoc}
 547      */
 548     public E getFirst() {
 549         E x = peekFirst();
 550         if (x == null) throw new NoSuchElementException();
 551         return x;
 552     }
 553 
 554     /**
 555      * @throws NoSuchElementException {@inheritDoc}
 556      */
 557     public E getLast() {
 558         E x = peekLast();
 559         if (x == null) throw new NoSuchElementException();
 560         return x;
 561     }
 562 
 563     public E peekFirst() {
 564         final ReentrantLock lock = this.lock;
 565         lock.lock();
 566         try {
 567             return (first == null) ? null : first.item;
 568         } finally {
 569             lock.unlock();
 570         }
 571     }
 572 
 573     public E peekLast() {
 574         final ReentrantLock lock = this.lock;
 575         lock.lock();
 576         try {
 577             return (last == null) ? null : last.item;
 578         } finally {
 579             lock.unlock();
 580         }
 581     }
 582 
 583     public boolean removeFirstOccurrence(Object o) {
 584         if (o == null) return false;
 585         final ReentrantLock lock = this.lock;
 586         lock.lock();
 587         try {
 588             for (Node<E> p = first; p != null; p = p.next) {
 589                 if (o.equals(p.item)) {
 590                     unlink(p);
 591                     return true;
 592                 }
 593             }
 594             return false;
 595         } finally {
 596             lock.unlock();
 597         }
 598     }
 599 
 600     public boolean removeLastOccurrence(Object o) {
 601         if (o == null) return false;
 602         final ReentrantLock lock = this.lock;
 603         lock.lock();
 604         try {
 605             for (Node<E> p = last; p != null; p = p.prev) {
 606                 if (o.equals(p.item)) {
 607                     unlink(p);
 608                     return true;
 609                 }
 610             }
 611             return false;
 612         } finally {
 613             lock.unlock();
 614         }
 615     }
 616 
 617     // BlockingQueue methods
 618 
 619     /**
 620      * Inserts the specified element at the end of this deque unless it would
 621      * violate capacity restrictions.  When using a capacity-restricted deque,
 622      * it is generally preferable to use method {@link #offer(Object) offer}.
 623      *
 624      * <p>This method is equivalent to {@link #addLast}.
 625      *
 626      * @throws IllegalStateException if the element cannot be added at this
 627      *         time due to capacity restrictions
 628      * @throws NullPointerException if the specified element is null
 629      */
 630     public boolean add(E e) {
 631         addLast(e);
 632         return true;
 633     }
 634 
 635     /**
 636      * @throws NullPointerException if the specified element is null
 637      */
 638     public boolean offer(E e) {
 639         return offerLast(e);
 640     }
 641 
 642     /**
 643      * @throws NullPointerException {@inheritDoc}
 644      * @throws InterruptedException {@inheritDoc}
 645      */
 646     public void put(E e) throws InterruptedException {
 647         putLast(e);
 648     }
 649 
 650     /**
 651      * @throws NullPointerException {@inheritDoc}
 652      * @throws InterruptedException {@inheritDoc}
 653      */
 654     public boolean offer(E e, long timeout, TimeUnit unit)
 655         throws InterruptedException {
 656         return offerLast(e, timeout, unit);
 657     }
 658 
 659     /**
 660      * Retrieves and removes the head of the queue represented by this deque.
 661      * This method differs from {@link #poll poll} only in that it throws an
 662      * exception if this deque is empty.
 663      *
 664      * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
 665      *
 666      * @return the head of the queue represented by this deque
 667      * @throws NoSuchElementException if this deque is empty
 668      */
 669     public E remove() {
 670         return removeFirst();
 671     }
 672 
 673     public E poll() {
 674         return pollFirst();
 675     }
 676 
 677     public E take() throws InterruptedException {
 678         return takeFirst();
 679     }
 680 
 681     public E poll(long timeout, TimeUnit unit) throws InterruptedException {
 682         return pollFirst(timeout, unit);
 683     }
 684 
 685     /**
 686      * Retrieves, but does not remove, the head of the queue represented by
 687      * this deque.  This method differs from {@link #peek peek} only in that
 688      * it throws an exception if this deque is empty.
 689      *
 690      * <p>This method is equivalent to {@link #getFirst() getFirst}.
 691      *
 692      * @return the head of the queue represented by this deque
 693      * @throws NoSuchElementException if this deque is empty
 694      */
 695     public E element() {
 696         return getFirst();
 697     }
 698 
 699     public E peek() {
 700         return peekFirst();
 701     }
 702 
 703     /**
 704      * Returns the number of additional elements that this deque can ideally
 705      * (in the absence of memory or resource constraints) accept without
 706      * blocking. This is always equal to the initial capacity of this deque
 707      * less the current {@code size} of this deque.
 708      *
 709      * <p>Note that you <em>cannot</em> always tell if an attempt to insert
 710      * an element will succeed by inspecting {@code remainingCapacity}
 711      * because it may be the case that another thread is about to
 712      * insert or remove an element.
 713      */
 714     public int remainingCapacity() {
 715         final ReentrantLock lock = this.lock;
 716         lock.lock();
 717         try {
 718             return capacity - count;
 719         } finally {
 720             lock.unlock();
 721         }
 722     }
 723 
 724     /**
 725      * @throws UnsupportedOperationException {@inheritDoc}
 726      * @throws ClassCastException            {@inheritDoc}
 727      * @throws NullPointerException          {@inheritDoc}
 728      * @throws IllegalArgumentException      {@inheritDoc}
 729      */
 730     public int drainTo(Collection<? super E> c) {
 731         return drainTo(c, Integer.MAX_VALUE);
 732     }
 733 
 734     /**
 735      * @throws UnsupportedOperationException {@inheritDoc}
 736      * @throws ClassCastException            {@inheritDoc}
 737      * @throws NullPointerException          {@inheritDoc}
 738      * @throws IllegalArgumentException      {@inheritDoc}
 739      */
 740     public int drainTo(Collection<? super E> c, int maxElements) {
 741         if (c == null)
 742             throw new NullPointerException();
 743         if (c == this)
 744             throw new IllegalArgumentException();
 745         final ReentrantLock lock = this.lock;
 746         lock.lock();
 747         try {
 748             int n = Math.min(maxElements, count);
 749             for (int i = 0; i < n; i++) {
 750                 c.add(first.item);   // In this order, in case add() throws.
 751                 unlinkFirst();
 752             }
 753             return n;
 754         } finally {
 755             lock.unlock();
 756         }
 757     }
 758 
 759     // Stack methods
 760 
 761     /**
 762      * @throws IllegalStateException {@inheritDoc}
 763      * @throws NullPointerException  {@inheritDoc}
 764      */
 765     public void push(E e) {
 766         addFirst(e);
 767     }
 768 
 769     /**
 770      * @throws NoSuchElementException {@inheritDoc}
 771      */
 772     public E pop() {
 773         return removeFirst();
 774     }
 775 
 776     // Collection methods
 777 
 778     /**
 779      * Removes the first occurrence of the specified element from this deque.
 780      * If the deque does not contain the element, it is unchanged.
 781      * More formally, removes the first element {@code e} such that
 782      * {@code o.equals(e)} (if such an element exists).
 783      * Returns {@code true} if this deque contained the specified element
 784      * (or equivalently, if this deque changed as a result of the call).
 785      *
 786      * <p>This method is equivalent to
 787      * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
 788      *
 789      * @param o element to be removed from this deque, if present
 790      * @return {@code true} if this deque changed as a result of the call
 791      */
 792     public boolean remove(Object o) {
 793         return removeFirstOccurrence(o);
 794     }
 795 
 796     /**
 797      * Returns the number of elements in this deque.
 798      *
 799      * @return the number of elements in this deque
 800      */
 801     public int size() {
 802         final ReentrantLock lock = this.lock;
 803         lock.lock();
 804         try {
 805             return count;
 806         } finally {
 807             lock.unlock();
 808         }
 809     }
 810 
 811     /**
 812      * Returns {@code true} if this deque contains the specified element.
 813      * More formally, returns {@code true} if and only if this deque contains
 814      * at least one element {@code e} such that {@code o.equals(e)}.
 815      *
 816      * @param o object to be checked for containment in this deque
 817      * @return {@code true} if this deque contains the specified element
 818      */
 819     public boolean contains(Object o) {
 820         if (o == null) return false;
 821         final ReentrantLock lock = this.lock;
 822         lock.lock();
 823         try {
 824             for (Node<E> p = first; p != null; p = p.next)
 825                 if (o.equals(p.item))
 826                     return true;
 827             return false;
 828         } finally {
 829             lock.unlock();
 830         }
 831     }
 832 
 833     /*
 834      * TODO: Add support for more efficient bulk operations.
 835      *
 836      * We don't want to acquire the lock for every iteration, but we
 837      * also want other threads a chance to interact with the
 838      * collection, especially when count is close to capacity.
 839      */
 840 
 841 //     /**
 842 //      * Adds all of the elements in the specified collection to this
 843 //      * queue.  Attempts to addAll of a queue to itself result in
 844 //      * {@code IllegalArgumentException}. Further, the behavior of
 845 //      * this operation is undefined if the specified collection is
 846 //      * modified while the operation is in progress.
 847 //      *
 848 //      * @param c collection containing elements to be added to this queue
 849 //      * @return {@code true} if this queue changed as a result of the call
 850 //      * @throws ClassCastException            {@inheritDoc}
 851 //      * @throws NullPointerException          {@inheritDoc}
 852 //      * @throws IllegalArgumentException      {@inheritDoc}
 853 //      * @throws IllegalStateException         {@inheritDoc}
 854 //      * @see #add(Object)
 855 //      */
 856 //     public boolean addAll(Collection<? extends E> c) {
 857 //         if (c == null)
 858 //             throw new NullPointerException();
 859 //         if (c == this)
 860 //             throw new IllegalArgumentException();
 861 //         final ReentrantLock lock = this.lock;
 862 //         lock.lock();
 863 //         try {
 864 //             boolean modified = false;
 865 //             for (E e : c)
 866 //                 if (linkLast(e))
 867 //                     modified = true;
 868 //             return modified;
 869 //         } finally {
 870 //             lock.unlock();
 871 //         }
 872 //     }
 873 
 874     /**
 875      * Returns an array containing all of the elements in this deque, in
 876      * proper sequence (from first to last element).
 877      *
 878      * <p>The returned array will be "safe" in that no references to it are
 879      * maintained by this deque.  (In other words, this method must allocate
 880      * a new array).  The caller is thus free to modify the returned array.
 881      *
 882      * <p>This method acts as bridge between array-based and collection-based
 883      * APIs.
 884      *
 885      * @return an array containing all of the elements in this deque
 886      */
 887     @SuppressWarnings("unchecked")
 888     public Object[] toArray() {
 889         final ReentrantLock lock = this.lock;
 890         lock.lock();
 891         try {
 892             Object[] a = new Object[count];
 893             int k = 0;
 894             for (Node<E> p = first; p != null; p = p.next)
 895                 a[k++] = p.item;
 896             return a;
 897         } finally {
 898             lock.unlock();
 899         }
 900     }
 901 
 902     /**
 903      * Returns an array containing all of the elements in this deque, in
 904      * proper sequence; the runtime type of the returned array is that of
 905      * the specified array.  If the deque fits in the specified array, it
 906      * is returned therein.  Otherwise, a new array is allocated with the
 907      * runtime type of the specified array and the size of this deque.
 908      *
 909      * <p>If this deque fits in the specified array with room to spare
 910      * (i.e., the array has more elements than this deque), the element in
 911      * the array immediately following the end of the deque is set to
 912      * {@code null}.
 913      *
 914      * <p>Like the {@link #toArray()} method, this method acts as bridge between
 915      * array-based and collection-based APIs.  Further, this method allows
 916      * precise control over the runtime type of the output array, and may,
 917      * under certain circumstances, be used to save allocation costs.
 918      *
 919      * <p>Suppose {@code x} is a deque known to contain only strings.
 920      * The following code can be used to dump the deque into a newly
 921      * allocated array of {@code String}:
 922      *
 923      * <pre>
 924      *     String[] y = x.toArray(new String[0]);</pre>
 925      *
 926      * Note that {@code toArray(new Object[0])} is identical in function to
 927      * {@code toArray()}.
 928      *
 929      * @param a the array into which the elements of the deque are to
 930      *          be stored, if it is big enough; otherwise, a new array of the
 931      *          same runtime type is allocated for this purpose
 932      * @return an array containing all of the elements in this deque
 933      * @throws ArrayStoreException if the runtime type of the specified array
 934      *         is not a supertype of the runtime type of every element in
 935      *         this deque
 936      * @throws NullPointerException if the specified array is null
 937      */
 938     @SuppressWarnings("unchecked")
 939     public <T> T[] toArray(T[] a) {
 940         final ReentrantLock lock = this.lock;
 941         lock.lock();
 942         try {
 943             if (a.length < count)
 944                 a = (T[])java.lang.reflect.Array.newInstance
 945                     (a.getClass().getComponentType(), count);
 946 
 947             int k = 0;
 948             for (Node<E> p = first; p != null; p = p.next)
 949                 a[k++] = (T)p.item;
 950             if (a.length > k)
 951                 a[k] = null;
 952             return a;
 953         } finally {
 954             lock.unlock();
 955         }
 956     }
 957 
 958     public String toString() {
 959         final ReentrantLock lock = this.lock;
 960         lock.lock();
 961         try {
 962             Node<E> p = first;
 963             if (p == null)
 964                 return "[]";
 965 
 966             StringBuilder sb = new StringBuilder();
 967             sb.append('[');
 968             for (;;) {
 969                 E e = p.item;
 970                 sb.append(e == this ? "(this Collection)" : e);
 971                 p = p.next;
 972                 if (p == null)
 973                     return sb.append(']').toString();
 974                 sb.append(',').append(' ');
 975             }
 976         } finally {
 977             lock.unlock();
 978         }
 979     }
 980 
 981     /**
 982      * Atomically removes all of the elements from this deque.
 983      * The deque will be empty after this call returns.
 984      */
 985     public void clear() {
 986         final ReentrantLock lock = this.lock;
 987         lock.lock();
 988         try {
 989             for (Node<E> f = first; f != null; ) {
 990                 f.item = null;
 991                 Node<E> n = f.next;
 992                 f.prev = null;
 993                 f.next = null;
 994                 f = n;
 995             }
 996             first = last = null;
 997             count = 0;
 998             notFull.signalAll();
 999         } finally {
1000             lock.unlock();
1001         }
1002     }
1003 
1004     /**
1005      * Returns an iterator over the elements in this deque in proper sequence.
1006      * The elements will be returned in order from first (head) to last (tail).
1007      *
1008      * <p>The returned iterator is a "weakly consistent" iterator that
1009      * will never throw {@link java.util.ConcurrentModificationException
1010      * ConcurrentModificationException}, and guarantees to traverse
1011      * elements as they existed upon construction of the iterator, and
1012      * may (but is not guaranteed to) reflect any modifications
1013      * subsequent to construction.
1014      *
1015      * @return an iterator over the elements in this deque in proper sequence
1016      */
1017     public Iterator<E> iterator() {
1018         return new Itr();
1019     }
1020 
1021     /**
1022      * Returns an iterator over the elements in this deque in reverse
1023      * sequential order.  The elements will be returned in order from
1024      * last (tail) to first (head).
1025      *
1026      * <p>The returned iterator is a "weakly consistent" iterator that
1027      * will never throw {@link java.util.ConcurrentModificationException
1028      * ConcurrentModificationException}, and guarantees to traverse
1029      * elements as they existed upon construction of the iterator, and
1030      * may (but is not guaranteed to) reflect any modifications
1031      * subsequent to construction.
1032      *
1033      * @return an iterator over the elements in this deque in reverse order
1034      */
1035     public Iterator<E> descendingIterator() {
1036         return new DescendingItr();
1037     }
1038 
1039     /**
1040      * Base class for Iterators for LinkedBlockingDeque
1041      */
1042     private abstract class AbstractItr implements Iterator<E> {
1043         /**
1044          * The next node to return in next()
1045          */
1046          Node<E> next;
1047 
1048         /**
1049          * nextItem holds on to item fields because once we claim that
1050          * an element exists in hasNext(), we must return item read
1051          * under lock (in advance()) even if it was in the process of
1052          * being removed when hasNext() was called.
1053          */
1054         E nextItem;
1055 
1056         /**
1057          * Node returned by most recent call to next. Needed by remove.
1058          * Reset to null if this element is deleted by a call to remove.
1059          */
1060         private Node<E> lastRet;
1061 
1062         abstract Node<E> firstNode();
1063         abstract Node<E> nextNode(Node<E> n);
1064 
1065         AbstractItr() {
1066             // set to initial position
1067             final ReentrantLock lock = LinkedBlockingDeque.this.lock;
1068             lock.lock();
1069             try {
1070                 next = firstNode();
1071                 nextItem = (next == null) ? null : next.item;
1072             } finally {
1073                 lock.unlock();
1074             }
1075         }
1076 
1077         /**
1078          * Returns the successor node of the given non-null, but
1079          * possibly previously deleted, node.
1080          */
1081         private Node<E> succ(Node<E> n) {
1082             // Chains of deleted nodes ending in null or self-links
1083             // are possible if multiple interior nodes are removed.
1084             for (;;) {
1085                 Node<E> s = nextNode(n);
1086                 if (s == null)
1087                     return null;
1088                 else if (s.item != null)
1089                     return s;
1090                 else if (s == n)
1091                     return firstNode();
1092                 else
1093                     n = s;
1094             }
1095         }
1096 
1097         /**
1098          * Advances next.
1099          */
1100         void advance() {
1101             final ReentrantLock lock = LinkedBlockingDeque.this.lock;
1102             lock.lock();
1103             try {
1104                 // assert next != null;
1105                 next = succ(next);
1106                 nextItem = (next == null) ? null : next.item;
1107             } finally {
1108                 lock.unlock();
1109             }
1110         }
1111 
1112         public boolean hasNext() {
1113             return next != null;
1114         }
1115 
1116         public E next() {
1117             if (next == null)
1118                 throw new NoSuchElementException();
1119             lastRet = next;
1120             E x = nextItem;
1121             advance();
1122             return x;
1123         }
1124 
1125         public void remove() {
1126             Node<E> n = lastRet;
1127             if (n == null)
1128                 throw new IllegalStateException();
1129             lastRet = null;
1130             final ReentrantLock lock = LinkedBlockingDeque.this.lock;
1131             lock.lock();
1132             try {
1133                 if (n.item != null)
1134                     unlink(n);
1135             } finally {
1136                 lock.unlock();
1137             }
1138         }
1139     }
1140 
1141     /** Forward iterator */
1142     private class Itr extends AbstractItr {
1143         Node<E> firstNode() { return first; }
1144         Node<E> nextNode(Node<E> n) { return n.next; }
1145     }
1146 
1147     /** Descending iterator */
1148     private class DescendingItr extends AbstractItr {
1149         Node<E> firstNode() { return last; }
1150         Node<E> nextNode(Node<E> n) { return n.prev; }
1151     }
1152 
1153     /**
1154      * Save the state of this deque to a stream (that is, serialize it).
1155      *
1156      * @serialData The capacity (int), followed by elements (each an
1157      * {@code Object}) in the proper order, followed by a null
1158      * @param s the stream
1159      */
1160     private void writeObject(java.io.ObjectOutputStream s)
1161         throws java.io.IOException {
1162         final ReentrantLock lock = this.lock;
1163         lock.lock();
1164         try {
1165             // Write out capacity and any hidden stuff
1166             s.defaultWriteObject();
1167             // Write out all elements in the proper order.
1168             for (Node<E> p = first; p != null; p = p.next)
1169                 s.writeObject(p.item);
1170             // Use trailing null as sentinel
1171             s.writeObject(null);
1172         } finally {
1173             lock.unlock();
1174         }
1175     }
1176 
1177     /**
1178      * Reconstitute this deque from a stream (that is,
1179      * deserialize it).
1180      * @param s the stream
1181      */
1182     private void readObject(java.io.ObjectInputStream s)
1183         throws java.io.IOException, ClassNotFoundException {
1184         s.defaultReadObject();
1185         count = 0;
1186         first = null;
1187         last = null;
1188         // Read in all elements and place in queue
1189         for (;;) {
1190             @SuppressWarnings("unchecked")
1191             E item = (E)s.readObject();
1192             if (item == null)
1193                 break;
1194             add(item);
1195         }
1196     }
1197 
1198 }
View Code

 

下面从ArrayBlockingQueue的创建,添加,取出,遍历这几个方面对LinkedBlockingDeque进行分析

1. 创建

下面以LinkedBlockingDeque(int capacity)来进行说明。

public LinkedBlockingDeque(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
}

说明:capacity是“链式阻塞队列”的容量。


LinkedBlockingDeque中相关的数据结果定义如下:

// “双向队列”的表头
transient Node<E> first;
// “双向队列”的表尾
transient Node<E> last;
// 节点数量
private transient int count;
// 容量
private final int capacity;
// 互斥锁 , 互斥锁对应的“非空条件notEmpty”, 互斥锁对应的“未满条件notFull”
final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();

说明:lock是互斥锁,用于控制多线程对LinkedBlockingDeque中元素的互斥访问;而notEmpty和notFull是与lock绑定的条件,它们用于实现对多线程更精确的控制。

双向链表的节点Node的定义如下:

static final class Node<E> {
    E item;       // 数据
    Node<E> prev; // 前一节点
    Node<E> next; // 后一节点

    Node(E x) { item = x; }
}

 

2. 添加

下面以offer(E e)为例,对LinkedBlockingDeque的添加方法进行说明。

public boolean offer(E e) {
    return offerLast(e);
}

offer()实际上是调用offerLast()将元素添加到队列的末尾。

offerLast()的源码如下:

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()的作用,是新建节点并将该节点插入到双向链表的末尾。它在插入节点前,会获取锁;操作完毕,再释放锁。

linkLast()的源码如下:

private boolean linkLast(Node<E> node) {
    // 如果“双向链表的节点数量” > “容量”,则返回false,表示插入失败。
    if (count >= capacity)
        return false;
    // 将“node添加到链表末尾”,并设置node为新的尾节点
    Node<E> l = last;
    node.prev = l;
    last = node;
    if (first == null)
        first = node;
    else
        l.next = node;
    // 将“节点数量”+1
    ++count;
    // 插入节点之后,唤醒notEmpty上的等待线程。
    notEmpty.signal();
    return true;
}

说明:linkLast()的作用,是将节点插入到双向队列的末尾;插入节点之后,唤醒notEmpty上的等待线程。


3. 删除

下面以take()为例,对LinkedBlockingDeque的取出方法进行说明。

public E take() throws InterruptedException {
    return takeFirst();
}

take()实际上是调用takeFirst()队列的第一个元素。

takeFirst()的源码如下:

public E takeFirst() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    // 获取锁
    lock.lock();
    try {
        E x;
        // 若“队列为空”,则一直等待。否则,通过unlinkFirst()删除第一个节点。
        while ( (x = unlinkFirst()) == null)
            notEmpty.await();
        return x;
    } finally {
        // 释放锁
        lock.unlock();
    }
}

说明:takeFirst()的作用,是删除双向链表的第一个节点,并返回节点对应的值。它在插入节点前,会获取锁;操作完毕,再释放锁。

unlinkFirst()的源码如下:

private E unlinkFirst() {
    // assert lock.isHeldByCurrentThread();
    Node<E> f = first;
    if (f == null)
        return null;
    // 删除并更新“第一个节点”
    Node<E> n = f.next;
    E item = f.item;
    f.item = null;
    f.next = f; // help GC
    first = n;
    if (n == null)
        last = null;
    else
        n.prev = null;
    // 将“节点数量”-1
    --count;
    // 删除节点之后,唤醒notFull上的等待线程。
    notFull.signal();
    return item;
}

说明:unlinkFirst()的作用,是将双向队列的第一个节点删除;删除节点之后,唤醒notFull上的等待线程。

 

4. 遍历

下面对LinkedBlockingDeque的遍历方法进行说明。

public Iterator<E> iterator() {
    return new Itr();
}

iterator()实际上是返回一个Iter对象。

Itr类的定义如下:

private class Itr extends AbstractItr {
    // “双向队列”的表头
    Node<E> firstNode() { return first; }
    // 获取“节点n的下一个节点”
    Node<E> nextNode(Node<E> n) { return n.next; }
}

Itr继承于AbstractItr,而AbstractItr的定义如下:

 

private abstract class AbstractItr implements Iterator<E> {
    // next是下一次调用next()会返回的节点。
    Node<E> next;
    // nextItem是next()返回节点对应的数据。
    E nextItem;
    // 上一次next()返回的节点。
    private Node<E> lastRet;
    // 返回第一个节点
    abstract Node<E> firstNode();
    // 返回下一个节点
    abstract Node<E> nextNode(Node<E> n);

    AbstractItr() {
        final ReentrantLock lock = LinkedBlockingDeque.this.lock;
        // 获取“LinkedBlockingDeque的互斥锁”
        lock.lock();
        try {
            // 获取“双向队列”的表头
            next = firstNode();
            // 获取表头对应的数据
            nextItem = (next == null) ? null : next.item;
        } finally {
            // 释放“LinkedBlockingDeque的互斥锁”
            lock.unlock();
        }
    }

    // 获取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);
            if (s == null)
                return null;
            else if (s.item != null)
                return s;
            else if (s == n)
                return firstNode();
            else
                n = s;
        }
    }

    // 更新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();
        }
    }

    // 返回“下一个节点是否为null”
    public boolean hasNext() {
        return next != null;
    }

    // 返回下一个节点
    public E next() {
        if (next == null)
            throw new NoSuchElementException();
        lastRet = next;
        E x = nextItem;
        advance();
        return x;
    }

    // 删除下一个节点
    public void remove() {
        Node<E> n = lastRet;
        if (n == null)
            throw new IllegalStateException();
        lastRet = null;
        final ReentrantLock lock = LinkedBlockingDeque.this.lock;
        lock.lock();
        try {
            if (n.item != null)
                unlink(n);
        } finally {
            lock.unlock();
        }
    }
}

 

LinkedBlockingDeque示例

 1 import java.util.*;
 2 import java.util.concurrent.*;
 3 
 4 /*
 5  *   LinkedBlockingDeque是“线程安全”的队列,而LinkedList是非线程安全的。
 6  *
 7  *   下面是“多个线程同时操作并且遍历queue”的示例
 8  *   (01) 当queue是LinkedBlockingDeque对象时,程序能正常运行。
 9  *   (02) 当queue是LinkedList对象时,程序会产生ConcurrentModificationException异常。
10  *
11  * @author skywang
12  */
13 public class LinkedBlockingDequeDemo1 {
14 
15     // TODO: queue是LinkedList对象时,程序会出错。
16     //private static Queue<String> queue = new LinkedList<String>();
17     private static Queue<String> queue = new LinkedBlockingDeque<String>();
18     public static void main(String[] args) {
19     
20         // 同时启动两个线程对queue进行操作!
21         new MyThread("ta").start();
22         new MyThread("tb").start();
23     }
24 
25     private static void printAll() {
26         String value;
27         Iterator iter = queue.iterator();
28         while(iter.hasNext()) {
29             value = (String)iter.next();
30             System.out.print(value+", ");
31         }
32         System.out.println();
33     }
34 
35     private static class MyThread extends Thread {
36         MyThread(String name) {
37             super(name);
38         }
39         @Override
40         public void run() {
41                 int i = 0;
42             while (i++ < 6) {
43                 // “线程名” + "-" + "序号"
44                 String val = Thread.currentThread().getName()+i;
45                 queue.add(val);
46                 // 通过“Iterator”遍历queue。
47                 printAll();
48             }
49         }
50     }
51 }

(某一次)运行结果:

ta1, ta1, tb1, tb1,

ta1, ta1, tb1, tb1, tb2, tb2, ta2, 
ta2, 
ta1, ta1, tb1, tb1, tb2, tb2, ta2, ta2, tb3, tb3, ta3, 
ta3, ta1, 
tb1, ta1, tb2, tb1, ta2, tb2, tb3, ta2, ta3, tb3, tb4, ta3, ta4, 
tb4, ta1, ta4, tb1, tb5, 
tb2, ta1, ta2, tb1, tb3, tb2, ta3, ta2, tb4, tb3, ta4, ta3, tb5, tb4, ta5, 
ta4, ta1, tb5, tb1, ta5, tb2, tb6, 
ta2, ta1, tb3, tb1, ta3, tb2, tb4, ta2, ta4, tb3, tb5, ta3, ta5, tb4, tb6, ta4, ta6, 
tb5, ta5, tb6, ta6,

结果说明:示例程序中,启动两个线程(线程ta和线程tb)分别对LinkedBlockingDeque进行操作。以线程ta而言,它会先获取“线程名”+“序号”,然后将该字符串添加到LinkedBlockingDeque中;接着,遍历并输出LinkedBlockingDeque中的全部元素。 线程tb的操作和线程ta一样,只不过线程tb的名字和线程ta的名字不同。
当queue是LinkedBlockingDeque对象时,程序能正常运行。如果将queue改为LinkedList时,程序会产生ConcurrentModificationException异常。

 


更多内容

1. Java多线程系列--“JUC集合”01之 框架

2. Java多线程系列目录(共xx篇)

 

posted on 2014-02-02 19:09  如果天空不死  阅读(16076)  评论(2)    收藏  举报