Java blocking queue in LinkedBlockingQueue

table of Contents

1.LinkedBlockingQueue Introduction

1.1BlockingQueue Interface

Like with ArrayBlockingQueue, LinkedBlockingQueue also achieved BlockingQueue interface.

1.2LinkedBlockingQueue

LinkedBlockingQueue

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

Guess you like

Origin www.cnblogs.com/yeyang/p/12580619.html