Blockingqueue queues in Java

Source: Internet
Author: User

Blockingqueue is located in the JDK5 new concurrent package, which solves the problem of how to "transfer" data efficiently and securely in multi-threading. These efficient and thread-safe queue classes provide great convenience for us to quickly build high-quality multi-threaded threads.

The blocking queue, as the name implies, it first is a queue, in the data structure, the queue is a linear table.

Through a Shared queue, we can make the data input from one end of the queue and output from the other. There are two main types of queues commonly used:
FIFO: The elements of the first inserted queue are also first out of the queue, similar to the queued functionality. To some extent, this kind of queue also embodies a kind of fairness.
Last in, first Out (LIFO): The element that is inserted into the queue is first out of the queue, which takes precedence over the most recent event, equivalent to the stack.

In a multithreaded environment, data sharing can easily be achieved through queues, such as the classic "producer" and "consumer" models, where the data sharing between the two can be conveniently implemented through queues.

Let's say we have a number of producer threads, and another number of consumer threads. If the producer thread needs to share the prepared data to the consumer thread and use the queue to pass the data, it is easy to solve the data sharing problem between them. But what if the producer and consumer are in a certain time period, in case the data processing speed does not match? Ideally, if the producer produces data at a faster rate than the consumer, and when the resulting data accumulates to a certain extent, then the producer must pause (block the producer thread) to wait for the consumer thread to finish processing the accumulated data, and vice versa.

Before the release of the JDK5 concurrent package, in a multithreaded environment, programmers can only rely on their own to manually control these implementation details, but also to take into account the efficiency and thread safety, which will bring our program a little complexity. So, the powerful concurrent package turned out, and brought us a strong blockingqueue. (Note: In the multithreaded realm, the so-called blocking, in some cases hangs the thread (that is, blocking), once the condition is met, the suspended thread will be automatically awakened).

  The maximum difference between a blocking queue and the normal queue (LinkedList or ArrayList, etc.) that we normally touch is that the blocking queue provides methods for blocking additions and blocking deletions .

* Blocking adds     a so-called blocking addition, which means that when the blocking queue element is full, the queue blocks the thread that joins the element until the queue element is not satisfied to wake the thread to perform the element join operation. * Blocking Delete     blocking delete means that when the queue element is empty, the thread that deletes the queue element is blocked until the queue is empty and then the delete operation (which typically returns the deleted element).

As a user of blockingqueue, we no longer have to worry about when we need to block threads, and when we need to wake up threads, because Blockingqueue is doing all of this for us.

Blockingqueue's core approach:

    • Insert Method:

      • Add (e E): Added successful return true, failed throw IllegalStateException exception
      • Offer (e): Success returns True if this queue is full, false.
      • Put (e): Inserts an element into the tail of this queue and blocks if the queue is full
    • Delete method:

      • Remove (Object o): Removes the specified element, returns true successfully, fails to return false
      • Poll (): Gets and removes the header element of this queue, and returns null if the queue is empty
      • Take (): Gets and removes this queue header element, which is blocked if there are no elements.
    • Check method

      • Element (): Gets but does not remove the header element of this queue, throws an exception without an element
      • Peek (): Gets the header of this queue without removing it, or null if the queue is empty.

Common blockingqueue:

①arrayblockingqueue

Arrayblockingqueue is a block-type queue that inherits from Abstractblockingqueue and indirectly implements the queue interface and collection interface. The bottom layer holds the data as an array (which can actually be thought of as an array of loops). Common operations include add, Offer,put,remove,poll,take,peek. the first three add offer put is an insert operation.  The following four methods are taken out of the operation.

It can be said that Arrayblockingqueue is a bounded blocking queue implemented by an array, which sorts elements in the first-in, FIFO-based way, where the put method and the take method are the blocking methods that are added and removed.

It is important to note that the blocking queues inside the Arrayblockingqueue are implemented by re-entering the lock reenterlock and condition conditional queues, so there is a difference between fair access and unfair access for elements in Arrayblockingqueue. For a fair access queue, the blocked thread can access the queue in a blocking order, that is, the blocked line enters upgradeable the queue. Instead of the fair queue, when the queue is available, the blocked thread will enter the competition for access to the resource, i.e. who first grabs the execution, without a fixed sequence.

②linkedblockingqueue

The Linkedblockingqueue is a blocking queue based on the underlying list, which maintains a data buffer queue (the queue is made up of linked lists). When a producer puts a data into the queue, the queue fetches the data from the producer, caches it inside the queue, and the producer returns immediately, and the producer queue is blocked only when the queue buffer reaches the maximum cache capacity (Linkedblockingqueue can specify the value through the constructor). Until the consumer consumes a piece of data from the queue, the producer thread is awakened, and the consumer's end of the process is based on the same principle. The structure diagram is as follows:

Linkedblockingqueue constructs when the size is not specified, the default size is Integer.max_value, and of course you can specify the size in the parameters of the constructor. Linkedblockingqueue does not accept null.
Linkedblockingqueue is able to handle concurrent data efficiently because it has separate locks on the producer and consumer sides to control data synchronization, which means that producers and consumers can operate the data in the queue in parallel with high concurrency, This improves the concurrency performance of the entire queue.

Maintain two locks in the Linkedblockingqueue, a lock for the queue, a lock for the team, which means that at the same time, only one thread can be queued, the remaining queued threads will be blocked, and another thread can execute the queue, The remaining threads that are executing the queue will be blocked. In other words, although the queue and the team two operations can only have one thread operation at the same time, but can be a queued thread and an outbound thread to execute together, it means that there may be two threads in the operation queues, so in order to maintain thread safety, Linkedblockingqueue uses a variable of type Atomicinterger to represent the number of elements in the current queue, so you can ensure that the underlying queue is thread-safe to operate between two threads.

Linkedblockingqueue can specify the capacity to maintain a queue internally, so there is a head node heads and a tail node last, the internal maintenance of two locks, one for the queue, one for the team, and the lock associated with the condition object. Important fields are:

    Capacity, if not specified, the value is Integer.max_value;    private final int capacity;    The element in the current queue    private final Atomicinteger count = new Atomicinteger ();    Queue head node, always meet Head.item==null    transient node<e> head;    The tail node of the queue, always satisfies last.next==null    private transient node<e> last;    Lock for out of team    private final Reentrantlock takelock = new Reentrantlock ();    When the queue is empty, save the thread that executes out of the team    private final Condition notempty = Takelock.newcondition ();    Lock for queue    private final Reentrantlock putlock = new Reentrantlock ();    When the queue is full, save the thread that executes the queued    private final Condition notfull = Putlock.newcondition ();

There are three ways to construct Linkedblockingqueue:

public Linkedblockingqueue () {this (integer.max_value);        } public linkedblockingqueue (int capacity) {if (capacity <= 0) throw new IllegalArgumentException ();        This.capacity = capacity;  last = head = new node<e> (null),//last and head exist when the queue is empty, so there is at least one node in the queue} public linkedblockingqueue (COLLECTION<?).        Extends e> c) {this (integer.max_value);        Final Reentrantlock putlock = This.putlock; Putlock.lock ();            Never contended, but necessary for visibility try {int n = 0;                For (e e:c) {if (E = = null) throw new NullPointerException ();                if (n = = capacity) throw new IllegalStateException ("Queue full");                Enqueue (New node<e> (E));            ++n;        } count.set (n);        } finally {Putlock.unlock (); }    }

As can be seen from the construction method of Linkedblockingqueue: When the parameterless construction method is called, the capacity is the maximum value of int; the queue contains at least one node, even if the queue is empty; Linkedblockingqueue does not support null elements.

Arrayblockingqueue and Linkedblockingqueue are the two most common, most common blocking queues.
Linkedblockingqueue saves the element with a linked list, inside of which is a node's inner class, which has a member variable node next, which forms the structure of a linked list, to get the next element, as long as you call next. Instead, Arrayblockingqueue saves the element based on an array.
Linkedblockingqueue Internal read/write (insert fetch) each has a lock, while the arrayblockingqueue reads and writes shares a lock.

③synchronousqueue

Unlike Arrayblockingqueue or Linkedblockingqueue,synchronousqueue, where there is no data cache space, you cannot call the Peek () method to see if there are data elements in the queue. Because the data element is only possible when you try to take away, not to take away and just want to spy on it, of course, the operation of traversing this queue is not allowed. The queue header element is the first thread that is queued to insert data, not the data to be exchanged. The data is passed directly between the paired producer and consumer threads and does not buffer the data into the queue. It can be understood that producers and consumers wait for each other, shake hands, and then leave together .

One usage scenario for Synchronousqueue is online constructor. Executors.newcachedthreadpool () uses Synchronousqueue, which creates new threads as needed (when a new task arrives), and if there are idle threads that are reused, the thread is reclaimed after 60 seconds of inactivity.

④linkedblockingdeque

Linkedblockingdeque is a linked-list-based, double-ended blocking queue. Similar to Linkedblockingqueue, the difference is that the class implements the Deque interface, and Linkedblockingqueue implements the queue interface.

The Linkedblockingdeque is an optional blocking queue, and if no capacity is set, then the capacity will be the maximum value of int.

The underlying data structure of the Linkedblockingdeque is a double-ended queue, which is implemented using a linked list:

 

The important fields of Linkedblockingdeque are as follows:

    The head node of the queue    transient node<e> first;    The tail node of the queue    transient node<e> last;    Number of elements in the queue    private transient int count;    Maximum number of elements in the queue    private final int capacity;    Lock    Final Reentrantlock lock = new Reentrantlock ();    When the queue is empty, the conditional queue of the take thread is blocked    private final Condition notempty = Lock.newcondition ();    When the queue is full, the conditional queue of the put thread is blocked    private final Condition notfull = Lock.newcondition ();

From the above field, you can see that there is only one lock in the linkedblockingdeque and two conditions associated with the lock, so you can infer that only one thread at a time can perform a queue or a queue operation at the head or end of the queue. It can be found that unlike Linkedblockingqueue, Linkedblockingqueue can have two threads performing operations at both ends.

Since the Linkedblockingdeque is a double-ended queue, it is possible to perform a team-in and out-of-line operation at the head of the squad, or at the end of the team.

There are three ways to construct Linkedblockingdeque:

Public Linkedblockingdeque () {This        (integer.max_value);    }    public linkedblockingdeque (int capacity) {        if (capacity <= 0) throw new IllegalArgumentException ();        This.capacity = capacity;    }    Public Linkedblockingdeque (collection<. extends e> c) {This        (integer.max_value);        Final Reentrantlock lock = This.lock;        Lock.lock (); Never contended, but necessary for visibility        try {for            (e e:c) {                if (E = = null)                    throw new Nullpo Interexception ();                if (!linklast (new node<e> (E)))                    throw new IllegalStateException ("Deque full");            }        } finally {            Lock.unlock ();        }    }

You can see that the structure and linkedblockingqueue of the three constructors are the same. But Linkedblockingqueue is the presence of a sentinel node that maintains the head node, while the Linkedblockingdeque is not.

Linkedblockingdeque and Linkedblockingqueue The same point is: ① based on the chain list ② capacity is optional, not set, is the maximum value of int linkedblockingdeque and linkedblockingqueue differ in that: ① double-ended linked list and single-linked list ② There is no sentinel node ③ a lock + Two conditions the same point of Linkedblockingdeque and Arrayblockingqueue is that the synchronization of the queue is maintained using a lock + two conditions.

Executorservice singlethreadexecutor = Executors.newsinglethreadexecutor ();
for (int i = 0; i < i++) {
Final int index = i;
Singlethreadexecutor.execute (New Runnable () {

@Override
public void Run () {
try {
SYSTEM.OUT.PRINTLN (index);
Thread.Sleep (2000);
} catch (Interruptedexception e) {
TODO auto-generated Catch block
E.printstacktrace ();
}
}
});
}

Blockingqueue queues in Java

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.