c++输出双向队列的全部元素_阻塞队列(4)LinkedBlockingDeque源码详解

问题LinkedBlockingDeque 是什么?优缺点?应用场景?源码实现?个人启发?LinkedBlockingDeque双向并发阻塞队列。所谓双向是指可以从队列的头和尾同时操作,并发只是线程安全的实现,阻塞允许在入队出队不满足条件时挂起线程,这里说的队列是指支持FIFO/FILO实现的链表。要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是fi...
摘要由CSDN通过智能技术生成

问题

  • LinkedBlockingDeque 是什么?
  • 优缺点?
  • 应用场景?
  • 源码实现?
  • 个人启发?

LinkedBlockingDeque

双向并发阻塞队列。

所谓双向是指可以从队列的头和尾同时操作,并发只是线程安全的实现,阻塞允许在入队出队不满足条件时挂起线程,这里说的队列是指支持FIFO/FILO实现的链表。

  1. 要想支持阻塞功能,队列的容量一定是固定的,否则无法在入队的时候挂起线程。也就是capacity是final类型的。
  2. 既然是双向链表,每一个结点就需要前后两个引用,这样才能将所有元素串联起来,支持双向遍历。也即需要prev/next两个引用。
  3. 双向链表需要头尾同时操作,所以需要first/last两个节点,当然可以参考LinkedList那样采用一个节点的双向来完成,那样实现起来就稍微麻烦点。
  4. 既然要支持阻塞功能,就需要锁和条件变量来挂起线程。这里使用一个锁两个条件变量来完成此功能。
38548707540ac756de5ba224dcd6400a.png

优缺点

优点当然是功能足够强大,同时由于采用一个独占锁,因此实现起来也比较简单。所有对队列的操作都加锁就可以完成。同时独占锁也能够很好的支持双向阻塞的特性。

凡事有利必有弊。缺点就是由于独占锁,所以不能同时进行两个操作,这样性能上就大打折扣。从性能的角度讲LinkedBlockingDeque要比LinkedQueue要低很多,比CocurrentLinkedQueue就低更多了,这在高并发情况下就比较明显了。

前面分析足够多的Queue实现后,LinkedBlockingDeque的原理和实现就不值得一提了,无非是在独占锁下对一个链表的普通操作。

使用案例

我们还是来看一个生产者消费者的例子。

生产者

private static class Producer implements Runnable{    private BlockingDeque queue;    public Producer(BlockingDeque queue) {        this.queue = queue;    }    @Override    public void run() {        while(true) {            try {                Integer num = ThreadLocalRandom.current().nextInt(100);                queue.put(num);                System.out.println(String.format("%s producer a num %d",Thread.currentThread().getName(),num));                Thread.sleep(1000);            } catch (InterruptedException e1) {                e1.printStackTrace();            }        }    }}

消费者

private static class Consumer implements Runnable{    private BlockingDeque queue;    public Consumer(BlockingDeque queue) {        this.queue = queue;    }    @Override    public void run() {        while(true) {            try {                System.out.println(String.format("%s consume a num %d",Thread.currentThread().getName(),queue.take()));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

测试代码

public static void main(String[] args) {    BlockingDeque queue = new LinkedBlockingDeque<>(100);    new Thread(new Producer(queue),"Producer").start();    new Thread(new Consumer(queue),"Consumer").start();}

测试日志:

Producer producer a num 62Consumer consume a num 62Producer producer a num 19Consumer consume a num 19Producer producer a num 26Consumer consume a num 26Consumer consume a num 39Producer producer a num 39

序列化

有趣的是此类支持序列化,但是Node并不支持序列化,因此fist/last就不能序列化,那么如何完成序列化/反序列化过程呢?

private void writeObject(java.io.ObjectOutputStream s)    throws java.io.IOException {    lock.lock();    try {        // Write out capacity and any hidden stuff        s.defaultWriteObject();        // Write out all elements in the proper order.        for (Node p = first; p != null; p = p.next)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值