Java 并发编程BlockingQueue、BlockingDeque

朱雀 2023-10-07 08:01 94阅读 0赞

一、BlockingQueue

BlockingQueue也叫做阻塞队列,在某些情况下对BlockingQueue的访问可能会造成阻塞。被阻塞的情况主要有如下两种:

  • 当队列满了的时候进行入队列操作
  • 当队列空了的时候进行出队列操作
    在这里插入图片描述

阻塞队列一共有四套方法用来进行增、删、查,当每套方法对应的操作不能马上执行时会有不同的反应,下面这个表格就分类列出了这些方法:


































操作 Throws Exception Special Value Blocks Times Out
Insert add(o) offer(o) put(o) offer(o, timeout, timeunit)
Remove remove(o) poll() take() poll(timeout, timeunit)
Examine element() peek() - -
  • ThrowsException:如果操作不能马上进行,则抛出异常
  • SpecialValue:如果操作不能马上进行,将会返回一个特殊的值,一般是true或者false
  • Blocks:如果操作不能马上进行,操作会被阻塞
  • TimesOut:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是true或者false

注意:

  • 不能向BlockingQueue中插入null,否则会报NullPointerException

BlockingQueue的实现类






























实现类 描述
ArrayBlockingQueue 特点:
ArrayBlockingQueue是一个有边界的阻塞队列,它的内部实现是一个数组。有边界的意思是它的容量是有限的,我们必须在其初始化的时候指定它的容量大小,容量大小一旦指定就不可改变。
排序方式:
ArrayBlockingQueue是以先进先出的方式存储数据,最新插入的对象是尾部,最新移出的对象是头部。
DelayQueue DelayQueue阻塞的是其内部元素,DelayQueue中的元素必须实现 java.util.concurrent.Delayed接口。Delayed接口getDelay()方法的返回值就是队列元素被释放前的保持时间,如果返回0或者一个负值,就意味着该元素已经到期需要被释放,此时DelayedQueue会通过其take()方法释放此对象。由于还继承了Comparable接口,所以DelayedQueue中的元素需要进行排序,一般情况,我们都是按元素过期时间的优先级进行排序。
LinkedBlockingQueue LinkedBlockingQueue阻塞队列大小的配置是可选的,如果我们初始化时指定一个大小,它就是有边界的,如果不指定,它就是无边界的。说是无边界,其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表。和ArrayBlockingQueue一样,LinkedBlockingQueue 也是以先进先出的方式存储数据,最新插入的对象是尾部,最新移出的对象是头部。
PriorityBlockingQueue PriorityBlockingQueue是一个没有边界的队列,它的排序规则和 java.util.PriorityQueue一样。需要注意,PriorityBlockingQueue中允许插入null对象。所有插入PriorityBlockingQueue的对象必须实现 java.lang.Comparable接口,队列优先级的排序规则就是按照我们对这个接口的实现来定义的。另外,我们可以从PriorityBlockingQueue获得一个迭代器Iterator,但这个迭代器并不保证按照优先级顺序进行迭代。
SynchronousQueue SynchronousQueue队列内部仅允许容纳一个元素。当一个线程插入一个元素后会被阻塞,除非这个元素被另一个线程消费。

其他队列


















队列 描述
PriorityQueue PriorityQueue 一个基于优先级的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。该队列不允许使用 null 元素也不允许插入不可比较的对象(没有实现Comparable接口的对象)。PriorityQueue 队列的头指排序规则最小那哥元素。如果多个元素都是最小值则随机选一个。PriorityQueue 是一个无界队列,但是初始的容量(实际是一个Object[]),随着不断向优先级队列添加元素,其容量会自动扩容,无需指定容量增加策略的细节。
ConcurrentLinkedQueue 一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。

类图

二、BlockingDeque

BlockingDeque 是java.util.concurrent包中的一个双端队列,向其中加入元素或从中取出元素都是线程安全的,如果不完全不能对BlockingDequeue插入或者取出元素,那么将会阻塞线程,deque 是 “Double Ended Queue”的简称。因此一个deque可以从两端插入和取出元素的。
如果线程同时生成和使用同一队列的元素,则可以使用BlockingDeque。 如果生产线程需要在队列的两端插入,并且消费线程需要从队列的两端删除,那么也可以使用它。 这是一个例子:
在这里插入图片描述
线程将产生元素并将其插入到队列的任一端。 如果双端队列当前已满,则插入线程将被阻塞,直到删除线程将一个元素从双端队列中取出。 如果deque当前为空,则删除线程将被阻塞,直到插入线程将一个元素插入到deque中。
BlockingDeque有4种不同的方法用于插入删除和检查双端队列中的元素。 在所请求的操作不能立即执行的情况下,每组方法的行为都不相同。 这里是一个表格的方法:


































操作 Throws Exception Special Value Blocks Times Out
Insert add(o)
addLast(o)
addFrist(o)
offer(o)
offerLast(o)
offerFrist(o)
put(o)
putLast(o)、putFrist(o)
offer(o, timeout, timeunit)
offerLast(o, timeout, timeunit)
offerFrist(o, timeout, timeunit)
Remove remove(o)
removeLast(o)
removeFrist(o)
poll()
polLastl()
pollFrist()
take()
takeLast()
takeFrist()
poll(timeout, timeunit)
pollLast(timeout, timeunit)
pollFrist(timeout, timeunit)
Examine element()
elementLast()
elementFrist()
peek()
peekLast()
peekFrist()
- -
  • ThrowsException:如果操作不能马上进行,则抛出异常
  • SpecialValue:如果操作不能马上进行,将会返回一个特殊的值,一般是true或者false
  • Blocks:如果操作不能马上进行,操作会被阻塞
  • TimesOut:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是true或者false

相关双端队列


















队列 描述
LinkedBlockingDeque LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列,即可以从队列的两端插入和移除元素。双向队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。
ArrayDeque 无容量大小限制,容量按需增长;非线程安全队列,无同步策略,不支持多线程安全访问;当用作栈时,性能优于Stack,当用于队列时,性能优于LinkedList;两端都可以操作;具有fail-fast特征;不能存储null;支持双向迭代器遍历

发表评论

表情:
评论列表 (有 0 条评论,94人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java 并发编程

    > 【面试】:并发和并行区别? 并发concurrency:多线程“同时”操作同一个资源,并不是真正的同时操作,而是交替操作,单核CPU的情况下,资源按时间段分配给多个线程。

    相关 Java 并发编程

    Java 并发编程 前言 并发编程可以总结为三个核心问题: 1. 分工:高效拆解任务并分配给线程 2. 同步:线程之间的合作 3. 互斥:同一时刻只允许一个

    相关 Java 并发编程

    多线程 1、操作系统有两个容易混淆的概念,进程和线程。 进程:一个计算机程序的运行实例,包含了需要执行的指令;有自己的独立地址空间,包含程序内容和数据;不同进程的地址...