【㉿Java并发】JUC提供了哪些阻塞队列

阻塞队列的处理方法

阻塞队列实现了 BlockingQueue 接口,并且有多组处理方法。

抛出异常

  • add方式是往队列里面添加元素,如果队列满了,会抛出异常
  • remove方法是删除元素,如果队列里面的不够删除了则抛出异常
  • element 方法是返回队列的头部节点,但是并不删除。如果用这个方法去操作一个空队列,会抛出和前面 remove 方法一样的异常:NoSuchElementException

返回结果但不抛出异常

  • offer 方法用来插入一个元素,并用返回值来提示插入是否成功。如果添加成功会返回 true,而如果队列已经满了,此时继续调用 offer 方法的话,它不会抛出异常,只会返回一个错误提示:false。
  • poll 方法表示移除并返回队列的头节点。如果当队列里面是空的,便会返回 null 作为提示。正因如此,是不允许往队列中插入 null 的,否则没有办法区分返回的 null 是一个提示还是一个真正的元素。
  • peek 方法返回队列的头元素但并不删除。如果队列里面是空的,它便会返回 null 作为提示。

阻塞

  • put 方法的作用是插入元素。如果队列已满就无法继续插入,这时它既不会立刻返回 false 也不会抛出异常,而是让插入的线程陷入阻塞状态,直到队列里有了空闲空间,此时队列就会让之前的线程解除阻塞状态,并把刚才那个元素添加进去。
  • take 方法的作用是获取并移除队列的头结点。通常在队列里有数据的时候会正常取出数据并删除;但是如果执行 take 的时候队列里无数据,则阻塞,直到队列里有数据;一旦队列里有数据了,就会立刻解除阻塞状态,并且取到数据。

抛出异常:add(e) 、remove()、element()
返回结果但不抛出异常:offer(e) 、poll()、peek()
阻塞:put(e) 、take()

JDK 8 中提供了七个阻塞队列

  • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
  • LinkedBlockingQueue :一个由链表结构组成的无界阻塞队列。
  • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列。
  • SynchronousQueue:一个不存储元素的阻塞队列。
  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

ArrayBlockingQueue

一个由数组结构组成的有界阻塞队列。初始时就要指定大小,内部用数组存储元素,利用ReentrantLock实现线程安全。初始创建指定容量后,不能再扩容。ArrayBlockingQueue采用全部锁,锁的粒度较大

ConcurrentLinkedQueue内部也是由单向链表的方式实现,默认存在一个哨兵节点,它是线程安全的无界非阻塞队列,与BlockingQueue不同的是,ConcurrentLinkedQueue通过CAS方式实现线程安全。

LinkedBlockingQueue

一个由链表结构组成的无界阻塞队列

如果不指定它的初始容量,则默认容量就是整型的最大值Integer.MAX_VALUE,由于容量非常大,LinkedBlockingQueue 也被称作无界队列。

SynchronousQueue

SynchronousQueue 最大的不同之处在于,它的容量为 0,所以没有一个地方来暂存元素,导致每次取数据都要先阻塞,直到有数据被放入;同理,每次放数据的时候也会阻塞,直到有消费者来取。需要注意的是,SynchronousQueue 的容量不是 1 而是 0,因为 SynchronousQueue 不需要去持有元素,它所做的就是直接传递(direct handoff)。由于每当需要传递的时候,SynchronousQueue 会把元素直接从生产者传给消费者,在此期间并不需要做存储,所以如果运用得当,它的效率是很高的。

SynchronousQueue 的 peek 方法永远返回 null

PriorityBlockingQueue

PriorityBlockingQueue 是一个支持优先级的无界阻塞队列,可以通过自定义类实现 compareTo() 方法来指定元素排序规则,或者初始化时通过构造器参数 Comparator 来指定排序规则。同时,插入队列的对象必须是可比较大小的,也就是 Comparable 的,否则会抛出 ClassCastException 异常。

DelayQueue

DelayQueue是一个无界阻塞延迟队列,具有“延迟”的功能。我们可以设定让队列中的任务延迟多久之后执行,比如 10 秒钟之后执行,这在例如“30 分钟后未付款自动取消订单”等需要延迟执行的场景中被大量使用。它是无界队列,放入的元素必须实现 Delayed 接口,而 Delayed 接口又继承了 Comparable 接口,所以自然就拥有了比较和排序的能力。

ConcurrentLinkedQueue

ConcurrentLinkedQueue并没有直接继承BlockingQueue,而是实现的Queue接口,少了take和put这两个阻塞方法。ConcurrentLinkedQueue内部也是由单向链表的方式实现,它是线程安全的无界非阻塞队列,与BlockingQueue不同的是,ConcurrentLinkedQueue通过CAS方式实现线程安全

ConcurrentLinkedQueue 使用 CAS 非阻塞算法 + 不停重试,来实现线程安全,适合用在不需要阻塞功能,且并发不是特别剧烈的场景

 

参考:

 

posted @ 2023-03-19 15:29  残城碎梦  阅读(15)  评论(0编辑  收藏  举报