Java 中的阻塞队列

1年前 (2023) 程序员胖胖胖虎阿
130 0 0

本文部分摘自《Java 并发编程的艺术》

阻塞队列概述

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列,这两个附加的操作支持阻塞的插入和移除方法:

  • 支持阻塞的插入方法:意思是当队列为满时,队列会阻塞插入元素的线程,直到队列不为满
  • 支持阻塞的移除方法:意思是当队列为空时,获取元素的线程会等待队列变为非空

阻塞队列通常用在生产者和消费者的场景,生产者是向队列添加元素的线程,消费者是从队列获取元素的线程。阻塞队列就是生产者用来存放元素,消费者用来获取元素的容器

在阻塞队列不可用时,这两个附加操作提供了四种处理方式:

抛出异常 返回特殊值 一直阻塞 超时退出
插入方法 add(o) offer(o) put(o) offer(o, timeout, timeunit)
移除方法 remove(o) poll() take(o) poll(o, timeout, timeunit)
检查方法 element() peek()
  • 抛出异常

    当队列满时,如果再往队列里插入元素,会抛出 IllegalStateException 异常。当队列空时,从队列里获取元素会抛出 NoSuchElementException 异常

  • 返回特殊值

    当往队列插入元素,会返回元素是否插入成功,成功返回 true,否则返回 false。如果是移除方法,则是从队列里取出一个元素,如果没有则返回 null

  • 一直阻塞

    当阻塞队列满时,如果生产者线程往队列里 put 元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断。当队列为空时,如果消费者线程从队列里 take 元素,队列会阻塞消费者线程,直到队列不为空

  • 超时退出

    当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定的时间,生产者线程就会退出

Java 里的阻塞队列

JDK7 提供了 7 个阻塞队列,如下:

1. ArrayBlockingQueue

ArrayBlockingQueue 是一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序,默认情况下不保证线程公平的访问队列

2. LinkedBlockingQueue

LinkedBlockingQueue 是一个用链表实现的有界阻塞队列,此队列的默认和最大长度为 Integer.MAX_VALUE,此队列按照先进先出的原则对元素进行排序

3. PriorityBlockingQueue

PriorityBlockingQueue 是一个支持优先级的无界阻塞队列,默认情况下元素采取自然顺序升序排序,也可以定义类实现 compareTo() 方法来指定元素排序规则,或者初始化队列时,指定构造参数 Comparator

4. DelayQueue

DelayQueue 是一个支持延时获取元素的无界阻塞队列,队列使用 PriorityQueue 来实现,队列中的元素必须实现 Delay 接口,在创建元素时可以指定多久才能从队列中获取当前元素,只有延迟期满才能从队列中提取元素

DelayQueue 可以运用在以下应用场景:

  • 缓存系统的设计:可以用 DelayQueue 保证缓存元素的有效期,使用一个线程循环查询 DelayQueue,一旦能从中获取元素,表示缓存有效期到了
  • 定时任务调度:使用 DelayQueue 保存当天将会执行的任务和执行时间,一旦从 DelayQueue 中获取到任务就开始执行

5. SynchronousQueue

SynchronousQueue 是一个不存储元素的阻塞队列,每一个 put 操作必须等待一个 take 操作,否则不能继续添加元素

6. LinkedTransferQueue

LinkedTransferQueue 是一个由链表结构组成的无界阻塞队列 TransferQueue 队列,相对于其他阻塞队列,LinkedTransferQueue 多了 tryTransfer 和 transfer 方法

  • transfer 方法

    如果当前有消费者正在等待接收元素(消费者使用 take 方法或带时间限制的 poll 方法时),transfer 方法可以把生产者传入的元素立刻 transfer(传输)给消费者。如果没有消费者在等待接收元素,transfer 方法会将元素存放在队列的 tail 节点,并等到该元素被消费者消费了才返回

  • tryTransfer 方法

    tryTransfer 方法是用来试探生产者传入的元素是否能直接传给消费者,如果没有消费者等待接收元素,则返回 false,和 transfer 方法的区别是 tryTransfer 方法无论消费者是否接收,方法立即返回,也可以带上时间限制

7. LinkedBlockingDeque

LinkedBlockingDeque 是一个由链表结构组成的双向阻塞队列,因为多了一个操作队列的入口,在多线程同时入队时,也就少了一半的竞争

版权声明:程序员胖胖胖虎阿 发表于 2023年9月3日 下午12:16。
转载请注明:Java 中的阻塞队列 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...