I am a little bit confused as to what the difference is between BlockingQueue/LinkedBlockingQueue and the new TransferQueue/LinkedTransferQueue types from jsr166y and java 7
From TransferQueue JavaDocs:
A BlockingQueue in which producers may wait for consumers to receive elements. A TransferQueue may be useful for example in message passing applications in which producers sometimes (using method transfer(E)) await receipt of elements by consumers invoking take or poll, while at other times enqueue elements (via method put) without waiting for receipt.
In other words, when you use BlockingQueue, you can only put element into queue (and block if queue is full). With TransferQueue, you can also block until other thread receives your element (you must use new transfer
method for that). This is the difference. With BlockingQueue, you cannot wait until other thread removes your element (only when you use SynchronousQueue, but that isn't really a queue).
Other than this, TransferQueue is also a BlockingQueue. Check out new available methods in TransferQueue: http://download.oracle.com/javase/7/docs/api/java/util/concurrent/TransferQueue.html (transfer, tryTransfer, hasWaitingConsumer, getWaitingConsumerCount).
Collections Framework Enhancements in Java SE 7 says explicitly:
The interface TransferQueue has been added. It is a refinement of the BlockingQueue interface in which producers can wait for consumers to receive elements. One implementation of the new interface is also included in this release, LinkedTransferQueue.
tryTransfer()
to offer an element only if there is a waiting consumer. –
Iago In short, BlockingQueue guarantees that the element made by producer must be in the queue, while TransferQueue gets one step further, it guarantees that the element "consumed" by some consumer.
A question long time ago and @Peter's answer is really elaborate. For people who wants to know how TransferQueue works in practice, maybe you can refer to the live demo below.
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;
public class TransferQueueExample {
TransferQueue<String> queue = new LinkedTransferQueue<String>();
class Producer implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 2; i++){
try{
System.out.println("Producer waiting to transfer: " + i);
queue.transfer("" + i);
System.out.println("Producer transfered: " + i);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 2; i++){
try{
Thread.sleep(2000);
System.out.println("Consumer waiting to comsume: " + i);
queue.take();
System.out.println("Consumer consumed: " + i);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
public static void main(String args[]){
TransferQueueExample example = new TransferQueueExample();
new Thread(example.new Producer()).start();
new Thread(example.new Consumer()).start();
}
}
The output is:
Producer waiting to transfer: 0
Consumer waiting to comsume: 0
Consumer consumed: 0
Producer transfered: 0
Producer waiting to transfer: 1
Consumer waiting to comsume: 1
Consumer consumed: 1
Producer transfered: 1
The transfer
is where the difference happens.
Transfers the element to a consumer, waiting if necessary to do so.
More precisely, transfers the specified element immediately if there exists a consumer already waiting to receive it (in take or timed poll), else waits until the element is received by a consumer.
As the javadoc, the transfer
will wait until the consumer has taken the product away.
That's the reason why "Producer waiting to transfer: 0"
is called firstly and after about 2 seconds, after it has been received by the consumer, the Producer transfered: 0
is called then.
Although there does seem to be some form of performance difference; see ArrayBlockingQueue vs LinkedTransferQueue and friends
© 2022 - 2024 — McMap. All rights reserved.