Java concurrency programming: blocking queues

Source: Internet
Author: User

Java concurrency programming: blocking queues

In the previous articles, we discussed the synchronization container (Hashtable, Vector), and also discussed the concurrent containers (Concurrenthashmap, copyonwritearraylist), which are very convenient for us to write multi-threaded program. Today we are going to discuss another class of containers: blocking queues.

In front of the queue we contacted are non-blocking queues, such as Priorityqueue, LinkedList (LinkedList is a doubly linked list, it implements the Dequeue interface).

One big problem with non-blocking queues is that it does not block the current thread, so it is cumbersome to implement additional synchronization policies and inter-thread wake-up policies in the face of similar consumer-producer models. But with the blocking queue it's different, it blocks the current thread, such as a thread fetching an element from an empty blocking queue, and the thread is blocked until the blocking queue has elements. When there are elements in the queue, the blocked thread is automatically awakened (no need for us to write code to wake up). This provides a great deal of convenience.

In this paper, we first describe the main blocking queues under the Java.util.concurrent package, then analyze the various methods in blocking queue and non-blocking queue, then analyze the implementation principle of blocking queue, and finally give a practical example and several usage scenarios.

I. Several major blocking queues

Two. Methods in blocking queues VS non-blocking queues

Three. How blocking queues are implemented

Four. Examples and usage scenarios

If there are any shortcomings please understand, and welcome criticism.

Please respect the author's labor results, reproduced please indicate the original link:

Http://www.cnblogs.com/dolphin0520/p/3932906.html

I. Several major blocking queues

Since Java 1.5, a number of blocking queues have been provided under the Java.util.concurrent package, mainly in the following sections:

Arrayblockingqueue: A blocking queue based on an array implementation that must be sized to create the Arrayblockingqueue object. It is also possible to specify fairness and unfairness, which by default is unfair, that is, queues that do not guarantee the longest waiting time have the highest priority to access the queue.

Linkedblockingqueue: A blocking queue based on a linked list that, if no capacity size is specified when creating a Linkedblockingqueue object, the default size is Integer.max_value.

Priorityblockingqueue: The above 2 queues are FIFO, and priorityblockingqueue is not, it sorts the elements according to the priority of the elements, in order of priority out of the team, each time the element is the highest priority element. Note that this blocking queue is an unbounded blocking queue, that is, the capacity is not capped (through the source can be known that it does not have a container full of signal flags), the first 2 kinds are bounded queues.

Delayqueue: Based on Priorityqueue, a delay-blocking queue in which elements in the delayqueue can be fetched from the queue only if their specified delay time is reached. Delayqueue is also an unbounded queue, so the operations (producers) that insert data into the queue are never blocked, and only the operations (consumers) that get the data are blocked.

Two. Methods in blocking queues VS non-blocking queues

1. Several main methods in non-blocking queues:

Add (E): Inserts the element e into the end of the queue, returns True if the insert succeeds, or throws an exception if the insert fails (that is, the queue is full);

Remove (): Removes the first element of the team, returns true if the removal succeeds, or throws an exception if the removal fails (the queue is empty);

Offer (E): Inserts element E at the end of the queue, returns True if the insert succeeds, or False if the insert fails (that is, the queue is full);

Poll (): Remove and get the first element of the team, if successful, return the first element of the team, otherwise return null;

Peek (): Gets the first element of the team and, if successful, returns the first element of the team; otherwise null

For non-blocking queues, it is generally recommended to use the offer, poll, and peek three methods, and the add and remove methods are not recommended. Because using the offer, poll, and peek three methods can determine the success of the operation by the return value, but using the Add and remove methods does not achieve this effect. Note that the methods in the non-blocking queue do not have synchronization measures.

2. Several main methods of blocking the queue:

The blocking queue includes most of the methods in the non-blocking queue, the 5 methods listed above exist in the blocking queue, but note that the 5 methods are synchronized in the blocking queue. In addition to this, the blocking queue provides another 4 very useful methods:

Put (e e)

Take ()

Offer (E e,long timeout, timeunit unit)

Poll (long timeout, timeunit unit)

  

The Put method is used to deposit elements to the end of the queue, and if the queues are full, wait;

The Take method is used to fetch elements from the first team, and if the queue is empty, wait;

The Offer method is used to deposit elements to the end of the queue, and if the queues are full, wait for a certain amount of time, and if the time period is reached, false if the insertion is not successful;

The poll method is used to take elements from the first team, and if the queue is empty, it waits for a certain amount of time, and returns null if the time period is reached, otherwise returns the acquired element;

Three. How blocking queues are implemented

Before talking about the non-blocking queue and blocking queue commonly used methods, the following to explore the implementation of the blocking queue principle, in this paper, Arrayblockingqueue for example, the other blocking queue implementation principle may and arrayblockingqueue some differences, but the general idea should be similar, Interested friends can self-view other blocking queue implementation source.

First look at several member variables in the Arrayblockingqueue class:

public class Arrayblockingqueue<e> extends Abstractqueue<e>implements blockingqueue<e> java.io.Serializable {private static final long Serialversionuid = -817911632652898426l;/** the queued items  */ Private final e[] items;/** items index for next take, poll or remove */private int takeindex;/** Items index for next put , offer, or add. */private int putindex;/** Number of items in the queue */private int count;/** Concurrency control uses the classic two-c Ondition algorithm* found in no textbook.*//** Main lock guarding All Access */private final Reentrantlock lock;/** Condi tion for waiting takes */private final Condition notempty;/** Condition for waiting puts */private final Condition notfull ;}

As you can see, the arrayblockingqueue is actually an array for storing elements, and takeindex and Putindex each represent the index of the first and last elements of the team, and count represents the number of elements in the queue.

Lock is a reentrant lock, Notempty and notfull are waiting conditions.

Here's a look at the constructor for Arrayblockingqueue, which has three overloaded versions:

public arrayblockingqueue (int capacity) {}public arrayblockingqueue (int capacity, Boolean fair) {}public Arrayblockingqueue (int capacity, Boolean fair,                          collection<? extends e> c) {}

The first constructor has only one parameter to specify capacity, the second constructor can specify capacity and fairness, and the third constructor can specify capacity, fairness, and initialization with another collection.

Then look at the implementation of its two key methods: put () and take ():

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 {        try {            while (count = = items.length)                notfull.await ();        } catch (Interruptedexception IE) {            Notfull.signal (); Propagate to non-interrupted thread            throw ie;        }        Insert (e);    } finally {        lock.unlock ();    }}

As can be seen from the implementation of the Put method, it acquires the lock first, and obtains the interruptible lock, then determines whether the current number of elements equals the length of the array, if equal, calls Notfull.await () to wait, and if the interrupt exception is caught, wakes the thread and throws an exception.

When awakened by another thread, insert the element through the Insert (e) method and finally unlock it.

Let's take a look at the implementation of the Insert method:

private void Insert (E x) {    Items[putindex] = x;    Putindex = Inc (PUTINDEX);    ++count;    Notempty.signal ();}

It is a private method that, after the insert succeeds, wakes the thread that is waiting to fetch the element through Notempty.

The following is the implementation of the Take () method:

Public E take () throws Interruptedexception {    final reentrantlock lock = This.lock;    Lock.lockinterruptibly ();    try {        try {            while (count = = 0)                notempty.await ();        } catch (Interruptedexception IE) {            Notempty.signal (); Propagate to non-interrupted thread            throw ie;        }        E x = extract ();        return x;    } finally {        lock.unlock ();    }}

Similar to the Put method implementation, except that the put method waits for the notfull signal, and the take method waits for the notempty signal. In the Take method, if an element can be taken, the element is obtained through the Extract method, and the following is the implementation of the Extract method:

Private E Extract () {    final e[] items = this.items;    E x = Items[takeindex];    Items[takeindex] = null;    Takeindex = Inc (TAKEINDEX);    --count;    Notfull.signal ();    return x;}

It is similar to the Insert method.

In fact, from here we should understand the implementation of the blocking queue principle, the fact that it and we use object.wait (), object.notify () and non-blocking queue implementation of the producer-consumer idea is similar, but it integrates these work together in the blocking queue implementation.

Four. Examples and usage scenarios

The following first implements the producer-consumer model using object.wait () and object.notify (), non-blocking queues:

public class Test {private int queuesize = 10;private priorityqueue<integer> queue = new Priorityqueue<integer&gt ;(queuesize);p ublic static void Main (string[] args) {test test = new test (); Producer Producer = Test.new Producer (); Consumer Consumer = test.new Consumer ();p roducer.start (); Consumer.start ();} Class Consumer extends thread{@Overridepublic void Run () {consume ();} private void Consume () {while (true) {synchronized (queue) {while (queue.size () = = 0) {try {System.out.println ("queue empty, waiting for data") ; Queue.wait ();} catch (Interruptedexception e) {e.printstacktrace (); Queue.notify ();}}          Queue.poll (); Each removal of the first element of the team queue.notify (); System.out.println ("Take an element from the queue, queue the remainder" +queue.size () + "elements");}}} Class Producer extends thread{@Overridepublic void run () {produce ();} private void produce () {while (true) {synchronized (queue) {while (queue.size () = = Queuesize) {try {System.out.println (" Queue full, waiting for free space "); queue.wait ();} catch (Interruptedexception e) {e.printstacktrace (); Queue.notify ();}}        Queue.offer (1);Insert one element at a time queue.notify (); SYSTEM.OUT.PRINTLN ("Inserts an element into the queue, the remaining space of the queue:" + (Queuesize-queue.size ()));}}}}

This is the classic producer-consumer pattern, implemented by blocking queues and object.wait () and Object.notify (), where Wait () and notify () are used primarily for inter-thread communication.

The specific methods of inter-threading communication (wait and use of notify) are described in subsequent chapters.

The following is the producer-consumer pattern implemented using a blocking queue:

public class Test {private int queuesize = 10;private arrayblockingqueue<integer> queue = new arrayblockingqueue< Integer> (queuesize);p ublic static void Main (string[] args)  {test test = new test (); Producer Producer = Test.new Producer (); Consumer Consumer = test.new Consumer ();p roducer.start (); Consumer.start ();} Class Consumer extends thread{@Overridepublic void Run () {consume ();} private void Consume () {while (true) {try {queue.take (); System.out.println ("Take an element from the queue, queue remaining" +queue.size () + "elements");} catch (Interruptedexception e) {e.printstacktrace ();}}}} Class Producer extends thread{@Overridepublic void run () {produce ();} private void produce () {while (true) {try {queue.put (1); SYSTEM.OUT.PRINTLN ("Inserts an element into the queue, the remaining space of the queue:" + (Queuesize-queue.size ()));} catch (Interruptedexception e) {e.printstacktrace ();}}}}

It has not been found that the use of blocking queue code is much simpler, and there is no need to consider the problem of synchronization and inter-thread communication separately.

In concurrent programming, it is generally recommended to use a blocking queue, so that the implementation can avoid unexpected errors in the program as much as possible.

The most classic scenario for blocking queues is the read and parse of the socket client data, the thread that reads the data constantly puts the data into the queue, and the parsing thread constantly fetches data from the queue. There are other similar scenarios where a blocking team can be used as long as the producer-consumer model is compatible.

Resources:

"Java Programming Practical"

http://ifeve.com/java-blocking-queue/

http://endual.iteye.com/blog/1412212

http://blog.csdn.net/zzp_403184692/article/details/8021615

Http://www.cnblogs.com/juepei/p/3922401.html

Java concurrency programming: blocking queues

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.