Java阻塞队列

概述

        队列是种只允许在表的前端进行删除操作,而在表的后端进行插入操作的线性表。阻塞队列和一般队列的不同之处在于阻塞队列是“阻塞”的,这里的阻塞指的是操作队 列的线程的一种状态。在阻塞队列中,线程阻塞有如下两种情况:
  • 消费者阻塞:在队列为空时·,消费者端的线程都会被自动阻塞(挂起),直到有数据放入队列,消费者线程会被自动唤醒并消费数据,如图所示
  • 生产者阻塞:在队列已满且没有可用空间时,生产者端的线程都会被自动阻塞(挂起),直到队列中有空的位置腾出,线程会被自动唤醒并生产数据,如图所示

一、阻塞队列的主要操作

阻塞队列的主要操作有插入操作和移除操作。插入操作有 a dd(e) 、o ffer(e)、 put(e)、offer(e,time,unit), 移除操作有 remove()、 poll ( )、take() 、poll(time,unit) ,具体介绍如下

1.插入操作

  • public abstract boolean add(E paramE): 将指定的元素插人队列中,在成功时返回 ture,如果当前没有可用的空间,则抛出IllegalStateException。如果该元素是null, 则抛出NullPointerException异常。Jdk源码的实现如下:


 

  • public abstract boolean offer(E paramE): 将指定的元素插入队列中,在成功时返回true,如果当前没有可用的空间,则返回false。jdk源码的实现如下:

  •  offer(E o, long timeout, TimeUnit unit): 将指定的元素插入队列中,可以设定等待的时间,如果在设定的等待时间内仍不能向队列中加入元素, 则返回 false。
  •  public abstract void put(E p aramE) throws InterruptedException 将指定的元素插入队列中,如果队列已经满了, 则阻塞、等待可用的队列空间的释放,直到有可用的队列空间释放且插入成功为止,JDK 源码的实现如下

2.获取数据操作

  • poll()取走队列队首的对象,如果取不到数据,则返回null。jdk源码的实现如下:
  •  poll(long timeout, T imeUnit unit ):取走列队首的对象,如果在指定的时间内队列有数据可取,则返回队列中的数据,否则等待一定时间 ,在等待超时并且没有数据可取时,返回null。
  • take () 取走列队首的对象,如果队列为空,则进入阻塞状态等待,知道队列有新的数据被加入,再及时取出新加入的数据。jdk源码的实现如下
  • drainTo(Collection collection) 一次性从队列中批量获取所有可用的数据对象,同时可以指定获取数据的个数,通过该方法可以提升获取数据的效率, 避免多次频繁操 作引起的队列锁定。 

二、Java中的阻塞队列实现

Java 中 的阻塞 队列有: ArrayBlockingQueue 、LinkedBlockingQueue 、PriorityBlockingQueue 、DelayQueue、SynchronousQueue、LinkedTransferQueue、LinkedBlockingDeque。具体功能如下:

  • ArrayBlockingQueue
        ArrayBlockingQueue 是基于数组实 现的有界阻塞 队列。ArrayBlockingQueue 队列按照 先进先出原则对元素进行排序,在 默认情 况下不保证元 素操 作的 公平性。
        队列操作的公平性指在生 产者线程或消费者线程发生 阻塞 后再次被 唤醒时,按照 阻塞的先 后顺序操作队列, 即先阻塞 生产者线程 优先向队列中插入元素,先阻塞的消费 者线程 优先从队列中 获取元素 。 因为保证公平性会降低吞吐 ,所 以如果要 处理的 数据 没有先后顺序, 则对 其可 以使用非 公平处理 的方式。我 们可以通 过以下代码创建一 个公平或者非公平的阻塞 队列:
  •  LinkedBlockingQueue

LinkedBlockingQueue是基于链表实现的阻塞队列,同ArrayBlockingQueue类似,此队列按照先进先出原则对元素进行排序,LinkedBlockingQueue对生产者端和消费者端分别采用两个独立的锁来控制数据同步,我们可以将队列头部的锁理解为写锁,尾部的锁理解成读锁,因此生产者和消费者可以基于各自独立的锁并行的操作队列中的数据,队列的并发性能较高,具体用法如下:

  • PriorityBlockingQueue

PriorityBlockingQueue是一个支持优先级的无界队列。元素在默认情况下采用自然顺序升序排序。可以自定义实现compareTo方法来指定元素进行排序规则,或者在初始化PriorityBlockingQueue时指定构造参数Comparator来实现对元素的排序。注意:如果两个元素的优先级相同,则不能保证该元素的存储和访问顺序。具体用法如下:

  •  DelayQueue

        DelayQueue是一个支持延时获取元素的无界阻塞队列,在队列底层使用PriorityQueue实现。DelayQueue队列中的元素必须实现Delayed接口,该接口定义了在创建元素时该元素的延迟时间,在内部通过为每个元素的操作加锁来保障数据的一致性。只有在延迟时间到后才能从队列中提取元素。我们可以将 DelayQueue运用于以下场景中

         缓存系统的设计:可以用 DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue一旦能从 DelayQueue 获取元素, 表示缓存的有效期到了。

        定时任务调度:使用 DelayQueue 保存即将执行的任务和执行时间,一旦从 DelayQueue 中获取元素,就表示任务开始执行,Java 中的 TimerQueue 就是使用 DelayQueue 实现的。

        在具体使用时,延迟对象必须先实现Delayed类并实现其getDelay方法和compareTo方法,才可以在延迟队列中使用:

  •  SynchronousQueue

SynchronousQueue时一个不存储元素的阻塞队列。SynchronousQueue中的每一个put操作都必须等待一个take操作完成,否则不能继续添加元素。我们可以将SynchronousQueue看作一个快递员,它负责把生产者线程的数据直接传递给消费线程,非常适用于传递型场景,比如将在一个线程中使用的数据传递给另一个线程使用。SynchronousQueue的吞吐量高于ArrayBlockingQueue 、LinkedBlockingQueue,具体的使用方法如下:

 

  •  LinkedTransferQueue

        LinkedTransferQueue是基于链表结构实现的无界阻塞TransferQueue队列。相对于其他阻塞队列,LinkedTransferQueue多了个transfer、tryTransfer和tryTransfer(E e,long timeout,TimeUint unit)方法。

        transfer方法:如果当前有消费者正在等待接收元素, transfer 方法就会直接把生产者传入的元素投递给消费者并返回 true。如果没有消费者在等待接收元素,transfer 方法就会将元素存放在队列的尾部( taiI )节点,直到该元素被消费后才返回。

        tryTransfer方法:首先尝试能否将生产者传入的元素直接传给消费者,如果没有消费者等待接收元素,则返回 false。和transfer方法的区别是,无论消费者是否接收元素,tryTransfer方法都立即返回,而 transfer 方法必须等到元素被消费后才返回。

        tryTransfer(E e,long timeout,TimeUint unit)方法:首先尝试生产者传入的元素直接传给消费者,如果没有消费者,则等待指定的时间,在超时后如果元素还没 有被消费,则返回 false ,否则返回true。

  • LinkedBlockingDeque

        LinkedBlockingDeque是基于链表结构实现的双向阻塞队列,可以在队列的两端分别执行插入和移出元素操作。这样,在多线程同时操作队列时,可以减少一半的锁资源竞争,提高队列的操作效率。

        LinkedBlockingDeque 相比其他阻塞 队列, 多了 addFirst、 addLast、 offer First、offerLast、 peekFirst 、 peekLast 等方法 First 结尾的方法 表示在 队列头部执行插入 (add )、获取( peek )、移除( offer )操 作;以 Last 结尾的方法 表示在 队列的尾部执行插 入、获取、移除操作。
        在初始化LinkedBlockingDeque 时,可以设置队列的大小以防止内存溢出,双向阻塞 队列也常被用于工作窃取模。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿德小仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值