Juc Source Analysis 19-Queue-priorityblockingqueue

Source: Internet
Author: User
Tags comparable

Priorityblockingqueue is an array-based, thread-safe, unbounded queue, with the same principle and internal structure as priorityqueue, just a thread-safe. Javadoc, 1: Theoretically unbounded, so adding elements can lead to outofmemoryerror;2. Add null;3 is not allowed. The added element uses the constructor to pass in the comparator sort, otherwise the natural ordering of the elements is used.

Priorityblockingqueue is based on priority, not FIFO, which is a good thing that can be used to implement a priority thread pool, high priority first execution, and low priority after execution. As with several previous queues, it is the inheritance Abstractqueue implementation of the Blockingqueue interface.

For the implementation of the priority, is to use an array to implement the heap, the approximate appearance of drawing a diagram is easy to understand:


When the top element of the heap is the smallest, the heap top element is guaranteed to be minimal for each left and right sub-heap.

Internal structure and construction:


An array-based implementation, if the construct does not have an incoming capacity, is the default size private static final int default_initial_capacity = 11;/** * Array maximum capacity */private static final int Max_array_size = integer.max_value-8;/** * Priority Queue array, remember that the 2 left and right child elements of queue[n] are in the position of the array in queue[2*n+1] and queue[2* (n+1)] */private Transient object[] queue;/** * Number of queue elements */private transient int size;/** * Comparator, constructed with the option to pass in, no null, then use the natural ordering of elements */private tra Nsient comparator<? Super e> comparator;/** * Re-entry Lock control multiple operations */private final reentrantlock lock;/** * queue is empty when conditional queue */private final Condition NotE mpty;/** * Spin lock */private transient volatile int allocationspinlock;/** * serialization using Priorityqueue, This priorityblockingqueue is almost exactly the same. */private priorityqueue q;/** * Default construction, with default capacity, no comparator */public priorityblockingqueue () {This (default_initial_capacity, null);} Public Priorityblockingqueue (Int. initialcapacity) {This (initialcapacity, null);} /** * Final call to construct */public priorityblockingqueue (int initialcapacity, comparator<? Super E> Comparator) {if (initialcapacity < 1) throw new IllegalArgumentException ();    This.lock = new Reentrantlock ();    This.notempty = Lock.newcondition ();    This.comparator = comparator; This.queue = new object[initialcapacity];}

There is nothing special about the internal structure and construction, the heap that implements the priority based on the array, remembers the left node of the array element Queue[n], and the right node queue[2* (n+1)], each time the team is queue[0].

Look at the usual methods:

Add, put, offer are the final call to the option () method:

Public Boolean offer (E e) {if (E = = null) throw new NullPointerException ();    Final Reentrantlock lock = This.lock;    Lock.lock ();    int n, Cap;    Object[] Array; while ((n = size) >= (Cap = (array = queue). Length)) Trygrow (array, CAP); If the number of elements is greater than the size of the array, then the automatic expansion, unbounded try {comparator<? super e> CMP = Comparator;//This looks at the structure when the argument, not the natural sort if (c MP = = null) siftupcomparable (n, E, array);        All inserts are adjusted from bottom up to else Siftupusingcomparator (n, E, array, CMP);        Size = n + 1; Notempty.signal ();    Notify non-empty conditional queue after add to take} finally {Lock.unlock (); } return true;  Array expansion private void Trygrow (object[] array, int oldcap) {lock.unlock ();//array expansion using spin lock, do not need to lock the main lock, first release object[] NewArray    = NULL;                                 if (Allocationspinlock = = 0 && unsafe.compareandswapint (this, Allocationspinlockoffset, 0, 1) {//cas occupies spin lock try {int newcap = Oldcap + ((Oldcap < 64)?                                  (Oldcap + 2)://Grow faster if small (oldcap >&gt ; 1)); Here the minimum capacity is doubled if (Newcap-max_array_size > 0) {//possible overflow int mincap = Oldcap +                1;                if (Mincap < 0 | | mincap > max_array_size) throw new OutOfMemoryError (); Newcap = max_array_size; After expansion, default maximum} if (Newcap > oldcap && queue = = array) NewArray = new object[        Newcap]; } finally {allocationspinlock = 0;//Free spin lock after capacity expansion} if (NewArray = = null)//To here if this thread is expanding NewArray certainly is    is not NULL, NULL is the other thread processing the expansion, then to other threads processing Thread.yield (); Lock.lock ();        The lock is re-entered here because there are additional operations if (NewArray! = null && queue = = array) {//here is not NULL then copy array queue = NewArray;    System.arraycopy (array, 0, NewArray, 0, Oldcap); }}//All inserts are adjusted from the bottom up private static <T> void siftupcomparable (int k, T x, object[] Array) {comparable<? super t> key = (comparable<? super t>) x;        while (k > 0) {int parent = (k-1) >>> 1;//Take the parent node of the inserted node Object e = array[parent];        if (Key.compareto ((T) e) >= 0)//If it is larger than the parent node, it does not matter to exit, directly placed in the K position break; Array[k] = e;    Smaller than the parent node, follow the K position to the parent node, and then continue looking up from the parent node for k = parent; } Array[k] = key;} All inserts are adjusted from the bottom up, similar to the Siftupcomparable method when using the construct incoming comparatorprivate static <T> void Siftupusingcomparator ( int k, T x, object[] array, comparator<?        Super T> CMP) {while (K > 0) {int parent = (k-1) >>> 1;        Object e = array[parent];        if (Cmp.compare (x, (T) e) >= 0) break;        Array[k] = e;    K = parent; } Array[k] = x;}

All the added elements are finally called the Offer method, 2 steps: Expansion + storage, the general process is:

1. Lock, check whether the number of elements is greater than or equal to the length of the array, if it is, then expansion, expansion does not need to use the main lock, the first release of the lock, the use of CAS spin lock, the capacity of the minimum doubling, the release of spin lock, there may be competition, check, whether the expansion, if the expansion

2. See if there are comparator in the construction of the parameter, there is the use, no natural sort, from the array to insert the parent node is larger, if larger than the parent node, then directly into the insertion position, or with the parent node, and then loop up to find, the number plus 1, notify the non-empty conditional queue take, Finally release the lock.


Look at the next few out-of-team operations:

Public E Poll () {final reentrantlock lock = This.lock;    Lock.lock ();    try {return dequeue ();    } finally {Lock.unlock ();    }}public E Take () throws Interruptedexception {final Reentrantlock lock = This.lock; Lock.lockinterruptibly ();    Response interrupt E result;        The try {while (result = dequeue ()) = = null) notempty.await ();//If Take, the array has no elements to block} finally {    Lock.unlock (); } return result;    Public E Poll (long timeout, timeunit unit) throws Interruptedexception {Long Nanos = Unit.tonanos (timeout);    Final Reentrantlock lock = This.lock; Lock.lockinterruptibly ();    Response interrupt E result; try {while (result = dequeue ()) = = null && nanos > 0) Nanos = Notempty.awaitnanos (Nanos);    Response time-out, time-out for each wakeup check} finally {Lock.unlock (); } return result;    Public E Peek () {final reentrantlock lock = This.lock;    Lock.lock (); try {return (size = = 0)? Null: (E) queue[0];//Just get the element,Do not remove} finally {Lock.unlock ();    }}//gets the basic call to this method private E dequeue () {int n = size-1;    if (n < 0) return null;        else {object[] array = queue;        E result = (e) array[0]; E x = (e) array[n]; Remove the last array element as a baseline array[n] = null; Out of the team, the last array is cleared, equivalent to the bottom of the heap of the most right leaf node to clear off the comparator<        Super E> CMP = comparator; if (CMP = = null) siftdowncomparable (0, x, array, n);        From top to bottom adjust else siftdownusingcomparator (0, x, array, n, CMP);        size = N;    return result;                                           }}//from top to bottom adjust private static <T> void siftdowncomparable (int k, T x, object[] array,         int n) {if (n > 0) {//element number greater than 0, array non-empty comparable<? Super t> key = (comparable<? super t>) x;           int half = n >>> 1; The parent node position of the last leaf node while (K < half) {int child = (k << 1) + 1;//position to be adjusted left node position Object c = Array[child];    Left node        int right = child + 1; Right node if (R < n && ((comparable<? Super T>) c). CompareTo ((T) array[right]) > 0) c = array[child = right];            Left and right node comparison, take small if (Key.compareto ((T) c) <= 0)//If the key to be adjusted is the smallest, then exit, direct assignment break; ARRAY[K] = c;        If key is not the smallest, then take the small left and right node to the adjustment position, then the small node position began to adjust k = child;    } Array[k] = key; }}

The overall flow of the team:

1. Lock, get queue[0], clear out the last leaf node of the heap, and use it as the comparison node;

2. Call the method from the top-down adjustment: To adjust the location node left and right node and before the leaf node comparison, if the previous leaf node is the smallest, then directly into the position to be adjusted, if the leaf node is small, then take the small one into the position to be adjusted, and the small part of the re-cycle to find, the number of It is basically half the number of elements to find a location.


Look at a remove, because the Remove method is used in the 2 adjustment method:

public boolean remove (Object o) {final reentrantlock lock = This.lock;    Lock.lock ();        try {int i = indexOf (o);//find o position in array if (i = =-1) return false; RemoveAt (i);    Remove to return true;    } finally {Lock.unlock ();        }}//o the position in the array private int indexOf (Object o) {if (o! = null) {object[] array = queue;        int n = size;    for (int i = 0; i < n; i++) if (O.equals (Array[i])) return i; } return-1;} Remove the element at the specified position in the array//similar to the dequeue of the previous take, dequeue is the position of remove 0, and the adjustment is also adjusted from the position of 0, where the private void removeAt is adjusted from the specified position (int    i) {object[] array = queue;    int n = size-1;    if (n = = i)//Removed last element array[i] = null;        else {e moved = (e) array[n];///Dequeue as well as the last leaf node as comparison array[n] = null; comparator<?        Super E> CMP = comparator; if (CMP = = null) siftdowncomparable (I, moved, array, n); Adjust an else Siftdownusi from a specified locationNgcomparator (i, moved, array, n, CMP);//After adjusting from top to bottom, if the comparison node is placed directly in the position to be adjusted, it can only indicate that the node is the smallest in the heap that is the heap top, but it does not indicate that it is looking up from this node for maximum// It needs to be adjusted from bottom up again if (array[i] = = moved) {if (CMP = = null) siftupcomparable (i, moved, ARRA            y);        else Siftupusingcomparator (i, moved, array, CMP); }} size = n;}

When remove, there are 2 adjustments, top-to-bottom adjustment, guaranteed to be minimal, and then upward adjustment.


Other methods do not look, all this means.


For my goal to continue to study, life not only, study not only.

Juc Source Analysis 19-Queue-priorityblockingqueue

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.