What is the difference between these two implementations? In which cases should be used one over another?
There is one more important point NOT mentioned in Hemz's answer.
From puredanger.github.io by Alex Miller:
BlockingQueue
expresses the concept of a queue that:
a producer can block when adding items to a queue until there is space available.
a consumer can block when removing an item from the queue until an item exists.
TransferQueue
takes this one step further and blocks on put until the item is actually consumed by a consumer (not just added to the queue). This new constraint is expressed in the key new method called transfer()
. The name is very descriptive – because the blocking occurs until a hand-off is complete from one thread to another, you are effectively transferring the item between threads (in a way that properly creates happens-before relationships in the Java Memory Model).
From baeldung.com
The implementation is actually similar to the BlockingQueue – but gives us the new ability to implement a form of backpressure. This means that, when the producer sends a message to the consumer using the transfer() method, the producer will stay blocked until the message is consumed.
The TransferQueue can be very useful when we do not want an over-producing producer that will flood the queue with messages, resulting in the OutOfMemory errors. In such design, the consumer will be dictating the speed at which the producer will produce messages.
From howtodoinjava.com
When a producer reaches to TransferQueue to transfer a message and there are consumers waiting to take message, then producer directly transfers the message to consumer.
If there is no consumer waiting, then producer will NOT directly put the message and return, rather it will wait for any consumer to be available to consume the message.
Other Points:
Source: puredanger.github.io
Several other methods are included as well: two forms of tryTransfer()
that perform a transfer but are either non-blocking (transfer only if it can be done immediately) or with a timeout. And then there are a couple of helper methods hasWaitingConsumer()
and getWaitingConsumerCount()
.
TransferQueue
is more generic and useful than SynchronousQueue
however as it allows you to flexibly decide whether to use normal BlockingQueue
semantics or a guaranteed hand-off. In the case where items are already in the queue, calling transfer will guarantee that all existing queue items will be processed before the transferred item.
A paper by William Scherer, Doug Lea, and Michael Scott that lays out the LinkedTransferQueue
algorithms and performance tests showing their improvements over the existing Java 5 alternatives. LinkedTransferQueue
outperforms SynchronousQueue
by a factor of 3x in unfair mode and 14x in fair mode.
Doug Lea says that capability-wise, LinkedTransferQueue
is actually a superset of ConcurrentLinkedQueue
, SynchronousQueue
(in “fair” mode), and unbounded LinkedBlockingQueues
. And it’s made better by allowing you to mix and match those features as well as take advantage of higher-performance implementation techniques.
As mentioned in this post by Alex Miller
TransferQueue is more generic and useful than SynchronousQueue however as it allows you to flexibly decide whether to use normal BlockingQueue semantics or a guaranteed hand-off. In the case where items are already in the queue, calling transfer will guarantee that all existing queue items will be processed before the transferred item.
SynchronousQueue implementation uses dual queues (for waiting producers and waiting consumers) and protects both queues with a single lock. The LinkedTransferQueue implementation uses CAS operations to form a nonblocking implementation and that is at the heart of avoiding serialization bottlenecks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With