SynchronousQueue详解

简介: SynchronousQueue详解

目录



SynchronousQueue详解


简介


SynchronousQueue是BlockingQueue的一种,所以SynchronousQueue是线程安全的。


SynchronousQueue和其他的BlockingQueue不同的是SynchronousQueue的capacity是0。


即SynchronousQueue不存储任何元素。


也就是说SynchronousQueue的每一次insert操作,必须等待其他线性的remove操作。而每一个remove操作也必须等待其他线程的insert操作。


这种特性可以让我们想起了Exchanger。和Exchanger不同的是,使用SynchronousQueue可以在两个线程中传递同一个对象。一个线程放对象,另外一个线程取对象。


举例说明


我们举一个多线程中传递对象的例子。还是举生产者消费者的例子,在生产者中我们创建一个对象,在消费者中我们取出这个对象。先看一下用CountDownLatch该怎么做:


@Test
    public void useCountdownLatch() throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        AtomicReference<Object> atomicReference= new AtomicReference<>();
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Runnable producer = () -> {
            Object object=new Object();
            atomicReference.set(object);
            log.info("produced {}",object);
            countDownLatch.countDown();
        };
        Runnable consumer = () -> {
            try {
                countDownLatch.await();
                Object object = atomicReference.get();
                log.info("consumed {}",object);
            } catch (InterruptedException ex) {
                log.error(ex.getMessage(),ex);
            }
        };
        executor.submit(producer);
        executor.submit(consumer);
        executor.awaitTermination(50000, TimeUnit.MILLISECONDS);
        executor.shutdown();
    }


上例中,我们使用AtomicReference来存储要传递的对象,并且定义了一个型号量为1的CountDownLatch。


在producer中,我们存储对象,并且countDown。


在consumer中,我们await,然后取出对象。


输出结果:


[pool-1-thread-1] INFO com.flydean.SynchronousQueueUsage - produced java.lang.Object@683d1b4b
[pool-1-thread-2] INFO com.flydean.SynchronousQueueUsage - consumed java.lang.Object@683d1b4b


可以看到传入和输出了同一个对象。


上面的例子我们也可以用SynchronousQueue来改写:


@Test
    public void useSynchronousQueue() throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        SynchronousQueue<Object> synchronousQueue=new SynchronousQueue<>();
        Runnable producer = () -> {
            Object object=new Object();
            try {
                synchronousQueue.put(object);
            } catch (InterruptedException ex) {
                log.error(ex.getMessage(),ex);
            }
            log.info("produced {}",object);
        };
        Runnable consumer = () -> {
            try {
                Object object = synchronousQueue.take();
                log.info("consumed {}",object);
            } catch (InterruptedException ex) {
                log.error(ex.getMessage(),ex);
            }
        };
        executor.submit(producer);
        executor.submit(consumer);
        executor.awaitTermination(50000, TimeUnit.MILLISECONDS);
        executor.shutdown();
    }


上面的例子中,如果我们使用synchronousQueue,则可以不用手动同步,也不需要额外的存储。


总结


如果我们需要在代码中用到这种线程中传递对象的情况,那么使用synchronousQueue吧。


本文的例子https://github.com/ddean2009/learn-java-collections

相关文章
|
存储 安全 Java
ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别?
ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别?
|
3月前
|
算法
LinkedBlockingQueue
LinkedBlockingQueue
30 0
|
6月前
|
存储 安全 Java
实现一个阻塞队列
实现一个阻塞队列
44 0
|
6月前
|
存储 消息中间件 安全
关于阻塞队列
关于阻塞队列
51 0
阻塞队列BlockingQueue
阻塞队列BlockingQueue
54 0
阻塞队列BlockingQueue
|
存储 缓存 安全
JUC之阻塞队列解读(BlockingQueue)
JUC之阻塞队列解读(BlockingQueue)
|
消息中间件 前端开发 中间件
阻塞队列的理解
阻塞队列的理解
|
算法
BlockingQueue二
接着上篇BlockingQueue没讲完的 LinkedTransferQueue LinkedTransferQueue是一个由链表结构组成的无界阻塞队列,相对于其它阻塞队列,LinkedBlockingQueue可以算是LinkedBlockingQueue与SynhronoousQueue结合,LinkedtransferQueue是一种无界阻塞队列,底层基于单链表实现,其内部结构分为数据节点、请求节点,基于CAS无锁算法实现
123 0
BlockingQueue二
|
缓存 安全 Java
JUC系列学习(四):线程池阻塞队列BlockingQueue及其相关实现ArrayBlockingQueue、LinkedBlockingQueue
线程池阻塞队列BlockingQueue及其相关实现ArrayBlockingQueue、LinkedBlockingQueue
114 0
|
存储 Java 索引
BlockingQueue
网上看了好多文章将线程池的但是似乎都没的多少人会详细讲解里面的任务队列,所以只有自己动手学习其中的任务队列 BlockingQueue
3066 0
BlockingQueue