In multithreaded applications , Queues need to handle multiple concurrent producers － Consumer solutions . The correct selection of concurrent queues is very important to achieve good performance in our algorithm .
First , We'll see some important differences between blocking queues and non blocking queues . then , We'll look at some implementations and best practices .
BlockingQueue Provides a simple thread safety mechanism . In this queue , Threads need to wait for queue availability . Producers will wait for available capacity before adding elements , And consumers will wait until the queue is empty . In order to implement this blocking mechanism ,BlockingQueue The interface is in the normal Queue Two functions are provided on the basis of function ：put and take. These functions are equivalent to the standard Queue Medium add and remove.
This queue uses arrays internally . therefore , It's a bounded queue , This means it has a fixed size . Suitable for producers / The consumer ratio is usually very low , We assign time-consuming tasks to multiple worker. Because this queue cannot grow indefinitely , So if there is a memory problem , You need to set the size limit as a security threshold .
ArrayBlockingQueue Yes put and take All operations use a lock . This ensures that the entry is not overridden , But it reduces performance .
LinkedBlockingQueue Use Linked list variant , Each queue item is a new node . Although this allows queues to be unrestricted in principle , But it still has Integer.MAX_VALUE The hard limit of . We can use constructors LinkedBlockingQueue（int capacity） Set queue size .
Queues use different locks put and take operation . So the two operations can be done in parallel and increase throughput .
because LinkedBlockingQueue It can be bounded or unbounded , Why should we use ArrayBlockingQueue？ Every time an item is added or removed from the queue ,LinkedBlockingQueue Both need to assign and deallocate nodes . therefore , If the queue grows and shrinks rapidly , be ArrayBlockingQueue Maybe a better choice .
It is said that LinkedBlockingQueue The performance of is unpredictable . let me put it another way , We always need to dissect our solutions to make sure we use the right data structures .
When we need to consume data in a specific order ,PriorityBlockingQueue Is our preferred solution . So ,PriorityBlockingQueue Using array based binary heaps .
Although a single locking mechanism is used internally , however take Operation can be done with put Simultaneous operation . This can be done with a simple spin lock .
A typical use case is to use tasks with different priorities . We don't want low priority tasks to replace high priority tasks .
When users can only take When an expired data item , We use DelayQueue . Interestingly , It is used internally PriorityQueue To sort data items by their expiration time .
Because this is not a universal queue , So it can't cover ArrayBlockingQueue or LinkedBlockingQueue So many scenes . for example , We can use this queue to implement a simple event loop , Similar to in NodeJS Event loop found in . We put asynchronous tasks in queues , For subsequent processing when they are due .
LinkedTransferQueue The introduction of a transfer Method . Although other queues are usually blocked when producing or consuming data items , but LinkedTransferQueue Allow producers to wait for data items to be consumed .
When we need to make sure that a particular item placed in the queue has been consumed by the consumer take When you take it away , have access to LinkedTransferQueue. Again , We can use this queue to implement a simple back pressure algorithm . actually , By stopping producers until they consume , Consumers can drive the resulting message flow .
A normal queue usually contains many data items , but SynchronousQueue There is always only one project at most . let me put it another way , We need to SynchronousQueue As a simple way to exchange some data between two threads .
When we have two threads that need to access shared state , We usually associate them with CountDownLatch Or other synchronization mechanisms . By using SynchronousQueue, We can avoid this kind of manual synchronization of threads .
ConcurrentLinkedQueue It is the only non blocking queue in this paper , therefore , It provides a kind of “ No waiting ” Algorithm , among add and poll It's thread safe , And return immediately . This queue uses CAS（Compare-And-Swap） Instead of locks .
In the internal , It's based on Maged M. Michael and Michael L. Scott Of Simple , Fast and practical non blocking and blocking concurrent queue algorithm .
For the modern world where blocking data structures are often forbidden Reaction system , It's the ideal choice .
On the other hand , If our consumers end up in a cycle of waiting , We should choose blocking as a better choice .