Chapter 8 ArrayBlockingQueue source code parsing and arraydeque source code parsing

Source: Internet
Author: User

Chapter 8 ArrayBlockingQueue source code parsing and arraydeque source code parsing

Note: You need to use ReentrantLock before reading this article or during the reading process. For details, see chapter 5 ReentrantLock source code parsing 1-obtain unfair lock and fair lock () chapter 6 ReentrantLock source code parsing 2 -- release Lock unlock () Chapter 7 ReentrantLock Summary

1. For ArrayBlockingQueue, master the following points:

  • Create
  • Join (add element)
  • Team out (delete element)

2. Create

  • Public ArrayBlockingQueue (int capacity, boolean fair)
  • Public ArrayBlockingQueue (int capacity)

Usage:

  • Queue <String> abq = new ArrayBlockingQueue <String> (2 );
  • Queue <String> abq = new ArrayBlockingQueue <String> (2, true );

By using this method, we can see that ArrayBlockingQueue supports ReentrantLock's fair lock mode and non-fair lock mode. For these two modes, check the article at the beginning of this article.

The source code is as follows:

Private final E [] items; // the underlying data structure private int takeIndex; // The index used for the next take/poll/remove (out of the queue) private int putIndex; // used for the next put/offer/add index (queued) private int count; // number of elements in the queue/** Concurrency control uses the classic two-condition algorithm found in any * textbook. * // ** Main lock guarding all access */private final ReentrantLock lock; // lock/** Condition for waiting takes */private final Condition notEmpty; // The waiting Condition/** Condition for waiting puts */private final Condition notFull; // The waiting ConditionView Code/*** create a queue, specify the queue capacity, specify the mode * @ param fair * true: the first thread operates first * false: random Order */public ArrayBlockingQueue (int capacity, boolean fair) {if (capacity <= 0) throw new IllegalArgumentException (); this. items = (E []) new Object [capacity]; // initialization class variable array items lock = new ReentrantLock (fair); // initialization class variable lock notEmpty = lock. newCondition (); // initialization class variable notEmpty Condition notFull = lock. newCondition (); // initialize the class variable notFull Condition}/*** to create a queue and specify the queue capacity, the default mode is non-fair mode * @ param capacity <1 will throw an exception */public ArrayBlockingQueue (int capacity) {this (capacity, false );}View Code

Note:

  • Composition of ArrayBlockingQueue: an array of objects + 1 lock ReentrantLock + 2 Condition Conditions
  • In the process of viewing the source code, we also need to imitate the use of conditional locks. This two-condition lock mode is a classic mode.

3. Join

3.1. public boolean offer (E e)

Principle:

  • Insert an element at the end of the team. If the queue is not full, true is returned immediately. If the queue is full, false is returned immediately.

Usage:

  • Abq. offer ("hello1 ");

Source code:

/*** Insert an element at the end of the team. * If the queue is not full, true is returned immediately. * If the queue is full, false is returned immediately. * Note: This method is generally better than add (), throwing an exception directly due to add () Failure */public boolean offer (E) {if (e = null) throw new NullPointerException (); final ReentrantLock lock = this. lock; lock. lock (); try {if (count = items. length) // return false when the array is full; else {// insert (e) When the array is not full; // insert an element return true ;}} finally {lock. unlock ();}}View Code private void insert (E x) {items [putIndex] = x; // insert element putIndex = inc (putIndex); // putIndex + 1 ++ count; // number of elements + 1/**** wake up a thread * If any thread is waiting for this condition, select a zone to wake up. * Before being awakened from the waiting state, the selected thread must obtain the lock again */notEmpty. signal ();}View Code/*** I + 1, array subscript + 1 */final int inc (int I) {return (++ I = items. length )? 0: I ;}View Code

The code is very simple. You only need to pay attention to the following points:

  • After the element is inserted, wake up the thread waiting for the notEmpty condition (that is, to obtain the element). This is similar to the producer-consumer mode.

 

3.2. public boolean offer (E e, long timeout, TimeUnit unit) throws InterruptedException

Principle:

  • Insert an element at the end of the team. If the array is full, wait until the following three conditions occur:
    • Awakened
    • Wait time timeout
    • The current thread is interrupted.

Usage:

Try {abq. offer ("hello2", 1000, TimeUnit. MILLISECONDS);} catch (InterruptedException e) {e. printStackTrace ();}View Code

Source code:

/*** Insert an element at the end of the team. * If the array is full, wait until the following three conditions occur: * 1. Wake up * 2. Wait time out * 3. The current thread is interrupted */public boolean offer (E e, long timeout, TimeUnit unit) throws InterruptedException {if (e = null) throw new NullPointerException (); long nanos = unit. toNanos (timeout); // converts the timeout value to a nanosecond final ReentrantLock = this. lock;/** lockInterruptibly (): * 1. Obtain the lock if the current thread is not interrupted. * 2. if the result is obtained successfully, the method ends. * 3. If the lock cannot be obtained, the current thread is blocked until the following situation occurs: * 1) the current thread (after being awakened) successfully acquires the lock * 2) the current thread is interrupted by other threads ** lock () * to obtain the lock. If the lock cannot be obtained, the current thread is blocked until the lock can be obtained and obtained successfully. */Lock. lockInterruptibly (); // Add an interrupt lock try {for (;) {if (count! = Items. length) {// The queue is not full of insert (e); return true;} if (nanos <= 0) // The returned false has timed out; try {/** to wait: * Three things may occur in this process: * 1. Wake up --> continue the current for (;) loop * 2. Timeout --> continue the current (;;) loop * 3. interrupted --> and then directly execute the catch part code */nanos = notFull. awaitNanos (nanos); // wait (in this process, time will be lost, and the thread may also be awakened)} catch (InterruptedException ie) {// The thread is interrupted notFull while waiting. signal (); // wake up other thread throw ie;} finally {lock. unlock ();}}View Code

Note:

  • AwaitNanos (nanos) is a method in AQS. It is not detailed here. If you are interested, check the source code of AQS.
  • For the differences between lockInterruptibly () and lock (), see the notes.

 

3.3. public void put (E e) throws InterruptedException

Principle:

  • Insert an element at the end of the team. If the queue is full, it will be blocked until the array is full or the thread is interrupted.

Usage:

Try {abq. put ("hello1");} catch (InterruptedException e) {e. printStackTrace ();}View Code

Source code:

/*** Insert an element at the end of the Team * If the queue is full, it will be blocked until the array is full or the thread is interrupted */public void put (E e) throws InterruptedException {if (e = null) throw new NullPointerException (); final E [] items = this. items; final ReentrantLock lock = this. lock; lock. lockInterruptibly (); try {while (count = items. length) // when the queue is full, it is always blocked here/** always waiting for the condition notFull, that is, it is awakened by other threads * (in fact, a thread leaves an element, then call notFull. signal () Wake up other threads waiting for this condition, and the queue is not slow.) */notFull. await ();} catch (InterruptedException ie) {// If notFull is interrupted. signal (); // wake up other threads waiting for this condition (notFull, namely, queuing) throw ie;} insert (e);} finally {lock. unlock ();}}View Code

 

4. Team-out

4.1. public E poll ()

Principle:

  • If no element exists, null is directly returned. If an element exists, the Header element is set to null. However, note that the header is changed at any time, not always items [0].

Usage:

Abq. poll ();

Source code:

/*** Team out */public E poll () {final ReentrantLock = this. lock; lock. lock (); try {if (count = 0) // if no element exists, null is directly returned instead of returning null; E x = extract (); return x;} finally {lock. unlock ();}}View Code/*** team out */private E extract () {final E [] items = this. items; E x = items [takeIndex]; // gets the team element items [takeIndex] = null; // leave the field of the element to the left blank. ** the takeIndex of the first team member is equal to or equal to 0, and the takeIndex of the second team member is equal to or equal to 1 *. (Note: after the team member leaves, the following array elements are not moved forward.) */takeIndex = inc (takeIndex); -- count; // Number of array elements-1 notFull. signal (); // The array is no longer satisfied. Wake up other threads waiting for the notFull condition to return x; // return the element of the queue}View Code

 

4.2. public E poll (long timeout, TimeUnit unit) throws InterruptedException

Principle:

  • Delete an element from the first element. If the array is not empty, it is out of the queue. If the array is empty and time-out, null is returned. If the array is empty and time-out, wait until the following three conditions occur:
    • Awakened
    • Wait time timeout
    • The current thread is interrupted.

Usage:

Try {abq. poll (1000, TimeUnit. MILLISECONDS);} catch (InterruptedException e) {e. printStackTrace ();}View Code

Source code:

/*** Delete an element from the first pair. * If the array is not empty, it leaves the queue. * If the array is empty, determine whether the time has timed out. If the array has timed out, return null * If the array is empty and the time has not timed out, wait until the following three conditions occur: * 1. Wake up * 2. Wait time timeout * 3. The current thread is interrupted */public E poll (long timeout, TimeUnit unit) throws InterruptedException {long nanos = unit. toNanos (timeout); // converts the time to a nanosecond final ReentrantLock = this. lock; lock. lockInterruptibly (); try {for (;) {if (count! = 0) {// The array is not empty. E x = extract (); // return x;} if (nanos <= 0) // return null upon time-out; try {/** wait: * Three things may occur in this process: * 1. Wake up --> continue the current (;;) loop * 2. Timeout --> continue the current for (;) loop * 3. be interrupted --> then directly execute the catch part of the Code */nanos = notEmpty. awaitNanos (nanos);} catch (InterruptedException ie) {notEmpty. signal (); // propagate to non-interrupted thread throw ie ;}} finally {lock. unlock ();}}View Code

 

4.3. public E take () throws InterruptedException

Principle:

  • Leave the queue Header element. If the queue is empty, it will be blocked until the array is not empty or the thread is interrupted.

Usage:

Try {abq. take ();} catch (InterruptedException e) {e. printStackTrace ();}View Code

Source code:

/*** Leave the queue Header element * If the queue is empty, it will be blocked until the array is not empty or the thread is interrupted */public E take () throws InterruptedException {final ReentrantLock lock = this. lock; lock. lockInterruptibly (); try {while (count = 0) // If the array is empty, it will always be blocked here/** keep waiting for the condition notEmpty, that is, it is awakened by other threads * (in fact, a thread queues an element and then calls notEmpty. signal () Wake up other threads waiting for this condition, and the queue is not empty.) */notEmpty. await ();} catch (InterruptedException ie) {notEmpty. signal (); // propagate to non-interrupted thread throw ie;} E x = extract (); return x;} finally {lock. unlock ();}}View Code

Summary:

1. Schematic diagram of the specific teams and teams: Here is only one case. See the dark part on the way to indicate that there are existing elements, and the light part has no elements.

 

How is the above situation formed? When the queue is full, the first element of the queue is items [0]. This is the case above.

If you want to leave the team again now, the element in the Team's head is items [1]. After you leave the team, the following situation is formed.

 

After leaving the queue, the first element is items [2]. Assuming that an element is about to be added to the queue, we can see from the inc method that it will be inserted into items [0, the formation of the team:

The above is the entire team-out process. The inc method has been provided above, And I will post it again here:

/*** I + 1, array subscript + 1 * Note: the reason for this write is as follows. */Final int inc (int I) {return (++ I = items. length )? 0: I ;}View Code

 

2. Comparison of Three Types of teams:

  • Offer (E): If the queue is not full, true is returned immediately; if the queue is full, false is returned immediately --> not blocked
  • Put (E): If the queue is full, it is blocked until the array is full or the thread is interrupted. --> Blocking
  • Offer (E e, long timeout, TimeUnit): insert an element at the end of the team. If the array is full, wait until the following three conditions occur: --> Blocking
    • Awakened
    • Wait time timeout
    • The current thread is interrupted.

 

3. Comparison of three types:

  • Poll (): If no element exists, null is directly returned. If an element exists
  • Take (): If the queue is empty, it will be blocked until the array is not empty or the thread is interrupted --> Blocking
  • Poll (long timeout, TimeUnit unit, until the following three situations occur:
    • Awakened
    • Wait time timeout
    • The current thread is interrupted.

Related Article

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.