BlockingQueue和TransferQueue之间的区别

时间:2011-09-06 09:17:43

标签: java concurrency jsr166

我对于BlockingQueue / LinkedBlockingQueue与来自jsr166y和java 7的新TransferQueue / LinkedTransferQueue类型之间的区别有点困惑

4 个答案:

答案 0 :(得分:64)

来自TransferQueue JavaDocs

  

BlockingQueue,其中生产者可以等待消费者接收元素。 TransferQueue可能在例如消息传递应用程序中很有用,其中生产者有时(使用方法转移(E))等待消费者调用take或poll接收元素,而在其他时候将元素排队(通过方法put)而不等待接收。

换句话说,当您使用BlockingQueue时,您只能将元素放入队列(如果队列已满,则阻止)。使用TransferQueue,您也可以阻止,直到其他线程接收到您的元素(您必须使用新的transfer方法)。这是不同的。使用BlockingQueue,您不能等到其他线程删除您的元素(仅当您使用SynchronousQueue时,但这不是真正的队列)。

除此之外,TransferQueue也是一个BlockingQueue。在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明确说明:

  

添加了接口TransferQueue。它是BlockingQueue接口的改进,生产者可以在其中等待消费者接收元素。此版本中还包含新接口的一个实现,LinkedTransferQueue。

答案 1 :(得分:2)

简而言之,BlockingQueue保证生产者生成的元素必须在队列中,而TransferQueue更进一步,它保证元素"消费"一些消费者。

答案 2 :(得分:1)

很久以前的问题和@Peter的回答非常详细。对于想要了解TransferQueue如何在实践中工作的人,也许你可以参考下面的现场演示。

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();
    }

}

输出结果为:

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

transfer是发生差异的地方。

  

将元素转移给消费者,并在必要时等待。

     

更确切地说,如果存在,则立即传输指定的元素   存在已经等待接收它的消费者(采取或定时   poll),否则等待消费者收到元素。

作为javadoc,transfer将等到消费者将产品拿走之后。

这就是为什么首先调用"Producer waiting to transfer: 0"的原因,大约2秒后,消费者收到Producer transfered: 0之后,就会调用var fundingDoc = XDocument.Load(pathToFundingInfo); // creating a lookup since there are multiple instances of the institutions var skdIds = fundingDoc.Descendants("skd").Elements("skosl") .ToLookup(s => (string)s.Element("skos"), s => (string)s.Parent.Attribute("id")); var outDoc = XDocument.Load(pathToUpdatedFile); foreach (var f in outDoc.Descendants("funding-source")) { if (f.Element("fundref-id") == null) { var name = (string)f.Element("institution-wrap"); var skd = skdIds[name].FirstOrDefault(); // just take the first one if (skd != null) f.Add(new XElement("fundref-id", skd.Substring("inst/".Length))); } } outDoc.Save(pathToUpdatedFile);

答案 3 :(得分:0)

虽然确实存在某种形式的性能差异;见ArrayBlockingQueue vs LinkedTransferQueue and friends