阻塞队列之LinkedBlockingQueue 源码
?
?
package java.util.concurrent;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.*;
?
?* @since 1.5
?* @author Doug Lea
?* @param <E> the type of elements held in this collection
?*
?*/
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
? ? ? ? implements BlockingQueue<E>, java.io.Serializable {
? ? private static final long serialVersionUID = -6903933977591709194L;
?
?
?
? ? /**
? ? ?* Linked list node class
? ? ?*/
? ? static class Node<E> {
? ? ? ? E item;
? ? ? ? /**
? ? ? ? ?* One of:
? ? ? ? ?* - the real successor Node
? ? ? ? ?* - this Node, meaning the successor is head.next
? ? ? ? ?* - null, meaning there is no successor (this is the last node)
? ? ? ? ?*/
?
? ? ? ? Node<E> next;
? ? ? ? Node(E x) { item = x; }
? ? }
?
? ? /** The capacity bound, or Integer.MAX_VALUE if none */
? ? private final int capacity;
?
? ? /** Current number of elements */
? ? private final AtomicInteger count = new AtomicInteger(0);
?
? ? /** Head of linked list */
? ? private transient Node<E> head;
?
? ? /** Tail of linked list */
? ? private transient Node<E> last;
?
? ? /** Lock held by take, poll, etc */
? ? private final ReentrantLock takeLock = new ReentrantLock();
?
? ? /** Wait queue for waiting takes */
? ? private final Condition notEmpty = takeLock.newCondition();
?
? ? /** Lock held by put, offer, etc */
? ? private final ReentrantLock putLock = new ReentrantLock();
?
? ? /** Wait queue for waiting puts */
? ? private final Condition notFull = putLock.newCondition();
?
? ? /**
? ? ?* Signals a waiting take. Called only from put/offer (which do not
? ? ?* otherwise ordinarily lock takeLock.)
? ? ?*/
? ? private void signalNotEmpty() {
? ? ? ? final ReentrantLock takeLock = this.takeLock;
? ? ? ? takeLock.lock();
? ? ? ? try {
? ? ? ? ? ? notEmpty.signal();
? ? ? ? } finally {
? ? ? ? ? ? takeLock.unlock();
? ? ? ? }
? ? }
?
? ? /**
? ? ?* Signals a waiting put. Called only from take/poll.
? ? ?*/
? ? private void signalNotFull() {
? ? ? ? final ReentrantLock putLock = this.putLock;
? ? ? ? putLock.lock();
? ? ? ? try {
? ? ? ? ? ? notFull.signal();
? ? ? ? } finally {
? ? ? ? ? ? putLock.unlock();
? ? ? ? }
? ? }
?
? ? /**
? ? ?*?
? ? ?* maintained by this queue. ?(In other words, this method must allocate
? ? ?* a new array). ?The caller is thus free to modify the returned array.
? ? ?*
? ? ?* <p>This method acts as bridge between array-based and collection-based
? ? ?* APIs.
? ? ?*
? ? ?* @return an array containing all of the elements in this queue
? ? ?*/
? ? public Object[] toArray() {
? ? ? ? fullyLock();
? ? ? ? try {
? ? ? ? ? ? int size = count.get();
? ? ? ? ? ? Object[] a = new Object[size];
? ? ? ? ? ? int k = 0;
? ? ? ? ? ? for (Node<E> p = head.next; p != null; p = p.next)
? ? ? ? ? ? ? ? a[k++] = p.item;
? ? ? ? ? ? return a;
? ? ? ? } finally {
? ? ? ? ? ? fullyUnlock();
? ? ? ? }
? ? }
?
? ? /**
? ? ?* Returns an array containing all of the elements in this queue, in
? ? ?* proper sequence; the runtime type of the returned array is that of
? ? ?* the specified array. ?If the queue fits in the specified array, it
? ? ?* is returned therein. ?Otherwise, a new array is allocated with the
? ? ?* runtime type of the specified array and the size of this queue.
? ? ?*
? ? ?* <p>If this queue fits in the specified array with room to spare
? ? ?* (i.e., the array has more elements than this queue), the element in
? ? ?* the array immediately following the end of the queue is set to
? ? ?* <tt>null</tt>.
? ? ?*
? ? ?* <p>Like the {@link #toArray()} method, this method acts as bridge between
? ? ?* array-based and collection-based APIs. ?Further, this method allows
? ? ?* precise control over the runtime type of the output array, and may,
? ? ?* under certain circumstances, be used to save allocation costs.
? ? ?*
? ? ?* <p>Suppose <tt>x</tt> is a queue known to contain only strings.
? ? ?* The following code can be used to dump the queue into a newly
? ? ?* allocated array of <tt>String</tt>:
? ? ?*
? ? ?* <pre>
? ? ?* ? ? String[] y = x.toArray(new String[0]);</pre>
? ? ?*
? ? ?* Note that <tt>toArray(new Object[0])</tt> is identical in function to
? ? ?* <tt>toArray()</tt>.
? ? ?*
? ? ?* @param a the array into which the elements of the queue are to
? ? ?* ? ? ? ? ?be stored, if it is big enough; otherwise, a new array of the
? ? ?* ? ? ? ? ?same runtime type is allocated for this purpose
? ? ?* @return an array containing all of the elements in this queue
? ? ?* @throws ArrayStoreException if the runtime type of the specified array
? ? ?* ? ? ? ? is not a supertype of the runtime type of every element in
? ? ?* ? ? ? ? this queue
? ? ?* @throws NullPointerException if the specified array is null
? ? ?*/
? ? // @SuppressWarnings("unchecked")
? ? public <T> T[] toArray(T[] a) {
? ? ? ? fullyLock();
? ? ? ? try {
? ? ? ? ? ? int size = count.get();
? ? ? ? ? ? if (a.length < size)
? ? ? ? ? ? ? ? a = (T[])java.lang.reflect.Array.newInstance
? ? ? ? ? ? ? ? ? ? (a.getClass().getComponentType(), size);
?
? ? ? ? ? ? int k = 0;
? ? ? ? ? ? for (Node<E> p = head.next; p != null; p = p.next)
? ? ? ? ? ? ? ? a[k++] = (T)p.item;
? ? ? ? ? ? if (a.length > k)
? ? ? ? ? ? ? ? a[k] = null;
? ? ? ? ? ? return a;
? ? ? ? } finally {
? ? ? ? ? ? fullyUnlock();
? ? ? ? }
? ? }
?
? ? public String toString() {
? ? ? ? fullyLock();
? ? ? ? try {
? ? ? ? ? ? return super.toString();
? ? ? ? } finally {
? ? ? ? ? ? fullyUnlock();
? ? ? ? }
? ? }
?
? ? /**
? ? ?* Atomically removes all of the elements from this queue.
? ? ?* The queue will be empty after this call returns.
? ? ?*/
? ? public void clear() {
? ? ? ? fullyLock();
? ? ? ? try {
? ? ? ? ? ? for (Node<E> p, h = head; (p = h.next) != null; h = p) {
? ? ? ? ? ? ? ? h.next = h;
? ? ? ? ? ? ? ? p.item = null;
? ? ? ? ? ? }
? ? ? ? ? ? head = last;
? ? ? ? ? ? // assert head.item == null && head.next == null;
? ? ? ? ? ? if (count.getAndSet(0) == capacity)
? ? ? ? ? ? ? ? notFull.signal();
? ? ? ? } finally {
? ? ? ? ? ? fullyUnlock();
? ? ? ? }
? ? }
?
? ? /**
? ? ?* @throws UnsupportedOperationException {@inheritDoc}
? ? ?* @throws ClassCastException ? ? ? ? ? ?{@inheritDoc}
? ? ?* @throws NullPointerException ? ? ? ? ?{@inheritDoc}
? ? ?* @throws IllegalArgumentException ? ? ?{@inheritDoc}
? ? ?*/
? ? public int drainTo(Collection<? super E> c) {
? ? ? ? return drainTo(c, Integer.MAX_VALUE);
?
? ? }
?
? ? /**
? ? ?* @throws UnsupportedOperationException {@inheritDoc}
? ? ?* @throws ClassCastException ? ? ? ? ? ?{@inheritDoc}
? ? ?* @throws NullPointerException ? ? ? ? ?{@inheritDoc}
? ? ?* @throws IllegalArgumentException ? ? ?{@inheritDoc}
? ? ?*/
? ? public int drainTo(Collection<? super E> c, int maxElements) {
? ? ? ? if (c == null)
? ? ? ? ? ? throw new NullPointerException();
? ? ? ? if (c == this)
? ? ? ? ? ? throw new IllegalArgumentException();
? ? ? ? boolean signalNotFull = false;
? ? ? ? final ReentrantLock takeLock = this.takeLock;
? ? ? ? takeLock.lock();
? ? ? ? try {
? ? ? ? ? ? int n = Math.min(maxElements, count.get());
? ? ? ? ? ? Node<E> h = head;
? ? ? ? ? ? int i = 0;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? while (i < n) {
? ? ? ? ? ? ? ? ? ? Node<E> p = h.next;
? ? ? ? ? ? ? ? ? ? c.add(p.item);
? ? ? ? ? ? ? ? ? ? p.item = null;
? ? ? ? ? ? ? ? ? ? h.next = h;
? ? ? ? ? ? ? ? ? ? h = p;
? ? ? ? ? ? ? ? ? ? ++i;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return n;
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? // Restore invariants even if c.add() threw
? ? ? ? ? ? ? ? if (i > 0) {
? ? ? ? ? ? ? ? ? ? // assert h.item == null;
? ? ? ? ? ? ? ? ? ? head = h;
? ? ? ? ? ? ? ? ? ? signalNotFull = (count.getAndAdd(-i) == capacity);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } finally {
? ? ? ? ? ? takeLock.unlock();
? ? ? ? ? ? if (signalNotFull)
? ? ? ? ? ? ? ? ?signalNotFull();
? ? ? ? }
? ? }
?
? ? /**
? ? ?* Returns an iterator over the elements in this queue in proper sequence.
? ? ?* The returned <tt>Iterator</tt> is a "weakly consistent" iterator that
? ? ?* will never throw {@link ConcurrentModificationException},
? ? ?* and guarantees to traverse elements as they existed upon
? ? ?* construction of the iterator, and may (but is not guaranteed to)
? ? ?* reflect any modifications subsequent to construction.
? ? ?*
? ? ?* @return an iterator over the elements in this queue in proper sequence
? ? ?*/
? ? public Iterator<E> iterator() {
? ? ? return new Itr();
? ? }
?
? ? private class Itr implements Iterator<E> {
? ? ? ? /*
? ? ? ? ?* Basic weakly-consistent iterator. ?At all times hold the next
? ? ? ? ?* item to hand out so that if hasNext() reports true, we will
? ? ? ? ?* still have it to return even if lost race with a take etc.
? ? ? ? ?*/
? ? ? ? private Node<E> current;
? ? ? ? private Node<E> lastRet;
? ? ? ? private E currentElement;
?
? ? ? ? Itr() {
? ? ? ? ? ? fullyLock();
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? current = head.next;
? ? ? ? ? ? ? ? if (current != null)
? ? ? ? ? ? ? ? ? ? currentElement = current.item;
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ?fullyUnlock();
? ? ? ? ? ? }
? ? ? ? }
?
? ? ? ? public boolean hasNext() {
? ? ? ? ? ? return current != null;
? ? ? ? }
?
? ? ? ? /**
? ? ? ? ?* Returns the next live successor of p, or null if no such.
? ? ? ? ?* ?
? ? ? ? ?* Unlike other traversal methods, iterators need to handle both:
? ? ? ? ?* - dequeued nodes (p.next == p)
? ? ? ? ?* - ?(possibly multiple) interior removed nodes (p.item == null)
? ? ? ? ?*/
? ? ? ? private Node<E> nextNode(Node<E> p) {
? ? ? ? ? ? for (; ;) { ??
? ? ? ? ? ? ? ? Node s = p.next;
? ? ? ? ? ? ? ? if (s == p)
? ? ? ? ? ? ? ? ? ?return head.next;
? ? ? ? ? ? ? ? if (s == null || s.item != null)
? ? ? ? ? ? ? ? ? ?return s;
? ? ? ? ? ? ? ? p = s;
? ? ? ? ? ? }
? ? ? ? }
?
? ? ? ? public E next() {
? ? ? ? ? ? fullyLock();
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? if (current == null)
? ? ? ? ? ? ? ? ? ? throw new NoSuchElementException();
? ? ? ? ? ? ? ? E x = currentElement;
? ? ? ? ? ? ? ? lastRet = current;
? ? ? ? ? ? ? ? current = nextNode(current);
? ? ? ? ? ? ? ? currentElement = (current == null) ? null : current.item;
? ? ? ? ? ? ? ? return x;
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ?fullyUnlock();
? ? ? ? ? ? }
? ? ? ? }
?
? ? ? ? public void remove() {
? ? ? ? ? ? if (lastRet == null)
? ? ? ? ? ? ? ? throw new IllegalStateException();
? ? ? ? ? ? fullyLock();
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? Node<E> node = lastRet;
? ? ? ? ? ? ? ? lastRet = null;
? ? ? ? ? ? ? ? for (Node<E> trail = head, p = trail.next;
? ? ? ? ? ? ? ? ? ? ?p != null;
? ? ? ? ? ? ? ? ? ? ?trail = p, p = p.next) {
? ? ? ? ? ? ? ? ? ? ?if (p == node) {
? ? ? ? ? ? ? ? ? ? ? ? ?unlink(p, trail);
? ? ? ? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?}
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? fullyUnlock();
? ? ? ? ? ? }
? ? ? ? }
? ? }
?
? ? /**
? ? ?* Save the state to a stream (that is, serialize it).
? ? ?*
? ? ?* @serialData The capacity is emitted (int), followed by all of
? ? ?* its elements (each an <tt>Object</tt>) in the proper order,
? ? ?* followed by a null
? ? ?* @param s the stream
? ? ?*/
? ? private void writeObject(java.io.ObjectOutputStream s)
? ? ? ? throws java.io.IOException {
?
? ? ? ? fullyLock();
? ? ? ? try {
? ? ? ? ? ? // Write out any hidden stuff, plus capacity
? ? ? ? ? ? s.defaultWriteObject();
?
? ? ? ? ? ? // Write out all elements in the proper order.
? ? ? ? ? ? for (Node<E> p = head.next; p != null; p = p.next)
? ? ? ? ? ? ? ? s.writeObject(p.item);
?
? ? ? ? ? ? // Use trailing null as sentinel
? ? ? ? ? ? s.writeObject(null);
? ? ? ? } finally {
? ? ? ? ? ? fullyUnlock();
? ? ? ? }
? ? }
?
? ? /**
? ? ?* Reconstitute this queue instance from a stream (that is,
? ? ?* deserialize it).
? ? ?* @param s the stream
? ? ?*/
? ? private void readObject(java.io.ObjectInputStream s)
? ? ? ? throws java.io.IOException, ClassNotFoundException {
? ? ? ? // Read in capacity, and any hidden stuff
? ? ? ? s.defaultReadObject();
?
? ? ? ? count.set(0);
? ? ? ? last = head = new Node<E>(null);
?
? ? ? ? // Read in all elements and place in queue
? ? ? ? for (;;) {
? ? ? ? ? ? // @SuppressWarnings("unchecked")
? ? ? ? ? ? E item = (E)s.readObject();
? ? ? ? ? ? if (item == null)
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? add(item);
? ? ? ? }
? ? }
}
?