58

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

4

4 回答 4

79

来自TransferQueue JavaDocs

生产者可以在其中等待消费者接收元素的 BlockingQueue。TransferQueue 例如在消息传递应用程序中可能很有用,其中生产者有时(使用方法 transfer(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)。


Java SE 7 中的 Collections Framework Enhancements明确表示:

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

于 2011-09-06T09:24:07.603 回答
7

简而言之,BlockingQueue 保证了生产者制作的元素必须在队列中,而 TransferQueue 更进一步,它保证了元素被某个消费者“消费”。

于 2014-02-10T04:11:45.410 回答
5

很久以前的一个问题,@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就是差异发生的地方。

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

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

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

这就是为什么"Producer waiting to transfer: 0"首先调用它,然后在大约 2 秒后,在消费者收到它之后,Producer transfered: 0再调用它。

于 2017-11-20T16:49:09.263 回答
-2

尽管似乎确实存在某种形式的性能差异;参见ArrayBlockingQueue vs LinkedTransferQueue 和朋友

于 2013-11-04T17:24:36.067 回答