java中的阻塞队列有哪些?

图片

问:java中的阻塞队列有哪些?

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

图片

 

ArrayBlockingQueue

ArrayBlockingQueue是基于数组实现的有界阻塞队列。ArrayBlockingQueue队列按照先进先出原则对元素进行排序,在默认情况下不保证元素操作的公平性。

 

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

图片

 

LinkedBlockingQueue

LinkedBlockingQueue是基于链表实现的阻塞队列,同ArrayListBlockingQueue类似,此队列按照先进先出原则对元素进行排序;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的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue。具体的使用方法如下:

图片

图片

 

LinkedTransferQueue

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

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

 

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

 

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

 

LinkedBlockingDeque

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

 

LinkedBlockingDeque相比其他阻塞队列,多了addFirst、addLast、offerFirst、offerLast、peekFirst、peekLast等方法。以First结尾的方法表示在队列头部执行插入(add)、获取(peek)、移除(offer)操作;以Last结尾的方法表示在队列的尾部执行插入、获取、移除操作。

 

在初始化LinkedBlockingDeque时,可以设置队列的大小以防止内存溢出,双向阻塞队列也常被用于工作窃取模式。

原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/90157.html

(0)
guozi的头像guozi
上一篇 2024年6月5日 上午11:58
下一篇 2024年6月5日 下午12:01

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注