1.LinkedBlockingQueue Introduction
1.1BlockingQueue Interface
Like with ArrayBlockingQueue, LinkedBlockingQueue also achieved BlockingQueue interface.
1.2LinkedBlockingQueue
LinkedBlockingQueue is a unidirectional blocking queue linked list implementation.
LinkedBlockingQueue capacity size can be specified at creation time, to prevent excessive expansion queue. If the queue capacity is not specified, the default size of the capacity Integer.MAX_VALUE.
1.3LinkedBlockingQueue principle and Data Structures
Description:
(01) head of the list is the header. When data is removed, are removed from the header at the head, dequeued.
(02) last in the list is the end of the table. When new data are inserted at the end of the table from the last enqueuing.
(03) count the actual size of the list, i.e. the number of nodes contained in this list.
(04) capacity is the capacity of the list, which is specified when creating the list.
(05) putLock is inserted in the lock, takeLock lock is removed; notEmpty "non-empty condition", notFull is "under conditions." For concurrency control list through them.
LinkedBlockingQueue in the realization of "multi-threaded exclusive access to competition for resources" for the "insert" and "remove (delete)" operations are using a different lock. For the insertion operation, synchronized by "Insert lock putLock"; for the unloading operation, synchronized by "getting lock takeLock".
2.LinkedBlockingQueue source code analysis
2.1 Create
public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalArgumentException(); this.capacity = capacity; last = head = new Node<E>(null); }
// queue capacity, not specified when creating the default is Integer.MAX_VALUE Private Final int Capacity; // number of elements in the queue Private Final AtomicInteger COUNT = new new AtomicInteger (); // head of the list (team head) transient the Node <E> head; // end of the list (the tail) Private transient the Node <E> Last; // "non-empty condition" for controlling "delete element" lock and the corresponding takeLock notEmpty Private Final of ReentrantLock takeLock = new new of ReentrantLock (); Private Final for condition Condition notEmpty = takeLock.newCondition (); //For controlling the "additive element" putLock and the corresponding lock "under conditions" notFull Private Final of ReentrantLock putLock = new new of ReentrantLock (); Private Final for condition Condition notFull putLock.newCondition = ();
static class Node<E> { E item; Node<E> next; Node(E x) { item = x; } }
2.2 put method
//put方法:若队列满,wait直到队列有空闲 public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; //To obtain a lock putLock.lockInterruptibly (); the try { // If the queue is full, the current (producer) notFull waiting thread blocked on the while (count.get () == Capacity) { notFull.await (); } // element into team the enqueue (the Node); // the "number of elements in the queue" +1, and return to the "number of elements in the original" c = count.getAndIncrement (); // if the element into the team after the queue is still full, wake-up wait on the notFull (producer) thread IF (C +. 1 < Capacity) notFull.signal (); } the finally { // release lock putLock.unlock (); } //If the number of any original queue element is 0, then the element into the team, the wake-up waiting on notEmpty (consumer) thread IF (C == 0 ) signalNotEmpty (); } Private void the enqueue (the Node <E> Node ) { // Assert putLock.isHeldByCurrentThread (); // Assert last.next == null; Last = last.next = Node; } Private void signalNotEmpty () { Final of ReentrantLock = takeLock the this .takeLock; takeLock.lock (); the try { notEmpty.signal (); } the finally { takeLock.unlock (); } }
2.3 take method
// Take method: If the queue is empty, wait until the queue is not empty public E Take () throws InterruptedException { E X; int C = -1 ; Final of AtomicInteger COUNT = the this .count; Final of ReentrantLock = takeLock the this .takeLock; // get lock takeLock.lockInterruptibly (); the try { // If the queue is empty, the current (consumers) on the thread blocked waiting notEmpty the while (count.get () == 0 ) { notEmpty.await (); } // element out team the X-= dequeue (); //The "number of elements in the queue" -1, and return to the "number of elements in the original" c = count.getAndDecrement (); // If, after the team elements, the remaining elements still queue, waiting in the wake of notEmpty (consumer ) thread IF (C>. 1 ) notEmpty.signal (); } the finally { // release lock takeLock.unlock (); } // if the original queue is full, the element after dequeue, the wakeup waiting on notFull (producer) thread IF (C == Capacity) signalNotFull (); return X; } Private E dequeue () { // Assert takeLock.isHeldByCurrentThread (); // Assert head.item == null; the Node <E> h = head; Node<E> first = h.next; h.next = h; // help GC head = first; E x = first.item; first.item = null; return x; } private void signalNotFull() { final ReentrantLock putLock = this.putLock; putLock.lock(); try { notFull.signal(); } finally { putLock.unlock(); } }