BlockingQueue的实现:SynchronousQueue和LinkedBlockingQueue之间有什么区别 [英] Implementation of BlockingQueue: What are the differences between SynchronousQueue and LinkedBlockingQueue

查看:823
本文介绍了BlockingQueue的实现:SynchronousQueue和LinkedBlockingQueue之间有什么区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到 BlockingQueue 的这些实现,并且无法了解它们之间的差异。我的结论到目前为止:


  1. 我不需要 SynchronousQueue

  2. LinkedBlockingQueue 确保FIFO 必须使用参数true创建,以使其成为FIFO

  3. SynchronousQueue

  4. 此实现的性能是否优于 LinkedBlockingQueue



    为了更复杂...为什么 Executors.newCachedThreadPool 使用SynchronousQueue( Executors.newSingleThreadExecutor Executors.newFixedThreadPool )使用LinkedBlockingQueue?



    > EDIT



    第一个问题已解决。但我仍然不明白为什么 Executors.newCachedThreadPool 在其他( Executors.newSingleThreadExecutor Executors.newFixedThreadPool )使用LinkedBlockingQueue时使用SynchronousQueue?



    我得到的是,使用SynchronousQueue,如果没有自由线程,生产者将被阻塞。但由于线程的数量实际上是无限的(如果需要将创建新线程),这将永远不会发生。那么为什么要使用SynchronousQueue?

    解决方案

    SynchronousQueue 种类的队列 - 它实现了队列的接口后面的集合方法(生产者等待直到消费者准备就绪,消费者等待直到生产者准备就绪)。



    因此,只有在需要特定语义的特殊情况下,您才需要它,例如单线程任务不排队进一步请求



    使用 SynchronousQueue 是性能。实现 SynchronousQueue 似乎被大量优化,所以如果你不需要任何超过一个会合点(如 Executors.newCachedThreadPool (),其中消费者是按需创建的,所以队列项不会累积),您可以通过使用 SynchronousQueue



    简单的综合测试显示,在一个简单的单一生产者 - 双核机器吞吐量单一消费者场景SynchronousQueue 是队列长度增加时 LinkedBlockingQueue ArrayBlockingQueue 的吞吐量的〜20倍。当队列长度增加时,吞吐量增加并且几乎达到 SynchronousQueue 的吞吐量。这意味着与其他队列相比, SynchronousQueue 在多核心机器上的同步开销低。但是,再次,只有在特定情况下,你需要伪装成 Queue 的集合点。



    编辑:



    这里是一个测试:

      public class Test {
    static ExecutorService e = Executors.newFixedThreadPool(2);
    static int N = 1000000;

    public static void main(String [] args)throws Exception {
    for(int i = 0; i< 10; i ++){
    int length = = 0)? 1:i * 5;
    System.out.print(length +\t);
    System.out.print(doTest(new LinkedBlockingQueue< Integer>(length),N)+\t);
    System.out.print(doTest(new ArrayBlockingQueue< Integer>(length),N)+\t);
    System.out.print(doTest(new SynchronousQueue< Integer>(),N));
    System.out.println();
    }

    e.shutdown();
    }

    private static long doTest(final BlockingQueue< Integer> q,final int n)throws Exception {
    long t = System.nanoTime

    e.submit(new Runnable(){
    public void run(){
    for(int i = 0; i< n; i ++)
    try {q.put(i);} catch(InterruptedException ex){}
    }
    });

    Long r = e.submit(new Callable< Long>(){
    public Long call(){
    long sum = 0;
    for = 0; i try {sum + = q.take();} catch(InterruptedException ex){}
    return sum;
    }
    } )。得到();
    t = System.nanoTime() - t;

    return(long)(1000000000.0 * N / t); // Throughput,items / sec
    }
    }

    结果在我的机器上:




    I see these implementation of BlockingQueue and can't understand the differences between them. My conclusion so far:

    1. I won't ever need SynchronousQueue
    2. LinkedBlockingQueue ensures FIFO, BlockingQueue must be created with parameter true to make it FIFO
    3. SynchronousQueue breaks most collections method (contains, size, etc)

    So when do I ever need SynchronousQueue? Is the performance of this implementation better than LinkedBlockingQueue?

    To make it more complicated... why does Executors.newCachedThreadPool use SynchronousQueue when the others (Executors.newSingleThreadExecutor and Executors.newFixedThreadPool) use LinkedBlockingQueue?

    EDIT

    The first question is solved. But I still don't understand why does Executors.newCachedThreadPool use SynchronousQueue when the others (Executors.newSingleThreadExecutor and Executors.newFixedThreadPool) use LinkedBlockingQueue?

    What I get is, with SynchronousQueue, the producer will be blocked if there is no free thread. But since the number of threads is practically unlimited (new threads will be created if needed), this will never happen. So why should it uses SynchronousQueue?

    解决方案

    SynchronousQueue is a very special kind of queue - it implements a rendezvous approach (producer waits until consumer is ready, consumer waits until producer is ready) behind the interface of Queue.

    Therefore you may need it only in the special cases when you need that particular semantics, for example, Single threading a task without queuing further requests.

    Another reason for using SynchronousQueue is performance. Implementation of SynchronousQueue seems to be heavily optimized, so if you don't need anything more than a rendezvous point (as in the case of Executors.newCachedThreadPool(), where consumers are created "on-demand", so that queue items don't accumulate), you can get a performance gain by using SynchronousQueue.

    Simple synthetic test shows that in a simple single producer - single consumer scenario on dual-core machine throughput of SynchronousQueue is ~20 time higher that throughput of LinkedBlockingQueue and ArrayBlockingQueue with queue length = 1. When queue length is increased, their throughput rises and almost reaches throughput of SynchronousQueue. It means that SynchronousQueue has low synchronization overhead on multi-core machines compared to other queues. But again, it matters only in specific circumstances when you need a rendezvous point disguised as Queue.

    EDIT:

    Here is a test:

    public class Test {
        static ExecutorService e = Executors.newFixedThreadPool(2);
        static int N = 1000000;
    
        public static void main(String[] args) throws Exception {    
            for (int i = 0; i < 10; i++) {
                int length = (i == 0) ? 1 : i * 5;
                System.out.print(length + "\t");
                System.out.print(doTest(new LinkedBlockingQueue<Integer>(length), N) + "\t");
                System.out.print(doTest(new ArrayBlockingQueue<Integer>(length), N) + "\t");
                System.out.print(doTest(new SynchronousQueue<Integer>(), N));
                System.out.println();
            }
    
            e.shutdown();
        }
    
        private static long doTest(final BlockingQueue<Integer> q, final int n) throws Exception {
            long t = System.nanoTime();
    
            e.submit(new Runnable() {
                public void run() {
                    for (int i = 0; i < n; i++)
                        try { q.put(i); } catch (InterruptedException ex) {}
                }
            });    
    
            Long r = e.submit(new Callable<Long>() {
                public Long call() {
                    long sum = 0;
                    for (int i = 0; i < n; i++)
                        try { sum += q.take(); } catch (InterruptedException ex) {}
                    return sum;
                }
            }).get();
            t = System.nanoTime() - t;
    
            return (long)(1000000000.0 * N / t); // Throughput, items/sec
        }
    }    
    

    And here is a result on my machine:

    这篇关于BlockingQueue的实现:SynchronousQueue和LinkedBlockingQueue之间有什么区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆