BlockingQueue与SynchronousQueue

BlockingQueue

BlockingQueue 是一个支持阻塞操作 的队列接口,位于 java.util.concurrent 包中。它的典型应用就是生产者-消费者模型

需要首先给队列设置容量

BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); // 容量=3

BlockingQueue 的四组 API

1. 抛异常

  • 当队列满时,再 add() 会抛异常;
  • 当队列空时,再 remove() 会抛异常。
scss 复制代码
add(e)       // 插入元素,成功返回 true,满时抛 IllegalStateException
remove()     // 移除队首元素,空时抛 NoSuchElementException
element()    // 查看队首元素,空时抛 NoSuchElementException

2. 返回特殊值

  • 满了插入失败返回 false
  • 空了移除失败返回 null
scss 复制代码
offer(e)     // 插入元素,成功返回 true,满时返回 false
poll()       // 移除队首元素,空时返回 null
peek()       // 查看队首元素,空时返回 null

3. 一直阻塞

  • 满了 put() 会一直阻塞,直到队列有空间;
  • 空了 take() 会一直阻塞,直到队列有元素。
scss 复制代码
put(e)       // 插入元素,满时阻塞
take()       // 移除并返回队首元素,空时阻塞

4.超时退出

  • 满了 offer(e, time, unit) 会等待指定时间,超时返回 false
  • 空了 poll(time, unit) 会等待指定时间,超时返回 null
scss 复制代码
offer(e, 2, TimeUnit.SECONDS)   // 等待 2 秒插入,失败返回 false
poll(2, TimeUnit.SECONDS)       // 等待 2 秒取出,失败返回 null
操作类型 抛异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查队首 element() peek() ------ ------

适合场景

  • 抛异常:适合严格要求,必须处理异常的场景。
  • 返回特殊值:适合可以容忍失败的场景。
  • 阻塞:适合生产者-消费者模型,不急着返回,等资源可用。
  • 超时:适合对实时性有要求的场景,不能无限等待。

SynchronousQueue

SynchronousQueue 是 Java 并发包里一个 非常特殊的 BlockingQueue 。它和其他 BlockingQueue(如 ArrayBlockingQueueLinkedBlockingQueue)不一样,它的容量永远是 0,没有任何内部缓冲。

特点

  1. 容量为 0
    • 不能存放任何元素。
    • put() 一个元素时,必须有另一个线程正在 take(),否则会阻塞。
    • take() 时也必须有线程 put(),否则也会阻塞。
  1. 一手交钱一手交货
    • 类似一个"当面交易"的模型。
    • 生产者线程和消费者线程必须同时到场,才能完成元素的交接。
  1. 线程间直接传递数据
    • 没有缓存区,数据不存储,而是 直接在两个线程之间传递

API 行为

  • put(e):如果没有消费者在等待,阻塞。
  • take():如果没有生产者在等待,阻塞。
  • offer(e, timeout, unit):在超时时间内,如果有消费者等待就成功,否则返回 false
  • poll(timeout, unit):在超时时间内如果有生产者等待就取到数据,否则返回 null

使用场景

  1. 线程间直接交换消息
    • 两个线程需要强同步(例如生产者和消费者一对一交接)。
  1. 线程池的工作队列(Executors.newCachedThreadPool 默认使用它)
    • 因为 SynchronousQueue 不存储任务,提交的任务必须马上被某个线程取走执行,如果没有空闲线程,就创建新线程。
    • 这也是为什么 CachedThreadPool 会无限制创建线程的原因。
相关推荐
Victor35611 小时前
https://editor.csdn.net/md/?articleId=139321571&spm=1011.2415.3001.9698
后端
Victor35611 小时前
Hibernate(89)如何在压力测试中使用Hibernate?
后端
灰子学技术13 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
Gogo81614 小时前
BigInt 与 Number 的爱恨情仇,为何大佬都劝你“能用 Number 就别用 BigInt”?
后端
fuquxiaoguang14 小时前
深入浅出:使用MDC构建SpringBoot全链路请求追踪系统
java·spring boot·后端·调用链分析
毕设源码_廖学姐14 小时前
计算机毕业设计springboot招聘系统网站 基于SpringBoot的在线人才对接平台 SpringBoot驱动的智能求职与招聘服务网
spring boot·后端·课程设计
野犬寒鸦16 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
逍遥德17 小时前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
MX_935917 小时前
Spring的bean工厂后处理器和Bean后处理器
java·后端·spring
程序员泠零澪回家种桔子18 小时前
Spring AI框架全方位详解
java·人工智能·后端·spring·ai·架构