SynchronousQueue 是不存储元素的同步队列,其核心是实现生产者与消费者间的直接交接:put 需等待 take、take 需等待 put,offer/poll 非阻塞但立即返回,size 始终为 0,适用于零缓冲的即时协作场景。
SynchronousQueue 是 Java 并发包(java.util.concurrent)中一种特殊的阻塞队列,它**不存储元素**——也就是说,它没有内部容量,不能“增”也不能“减”传统意义上的队列元素。
为什么说它不支持常规的“增减”操作?
它的设计目标是实现**直接交接(hand-off)**:每个插入操作(put)必须等待另一个线程执行对应的移除操作(take),反之亦然。没有缓冲空间,没有暂存元素。
-
offer(e)和put(e):不是“把元素加进去”,
而是“尝试交给另一个正在等待取走它的线程”。如果此时没有匹配的消费者,
offer立即返回false,put则阻塞直到有线程调用take。 -
poll()和take():不是“从队列里取出一个已有元素”,而是“尝试从某个正在等待交付的生产者那里接收一个元素”。如果没有匹配的生产者,poll返回null,take阻塞等待。 -
size()始终返回0;isEmpty()始终返回true—— 因为它真的不保存任何东西。
常见使用场景:线程间“一来一回”的即时协作
它适合用于需要严格配对、零延迟传递的场景,比如:
- 工作窃取线程池(如
ForkJoinPool内部)中任务的快速交接 - 生产者-消费者模型中要求“生产即消费”,不允许积压
- 构建无缓冲的信号通道(例如:一个线程通知另一个线程“我准备好了”,对方立即响应)
简单示例:put/take 配对才能完成一次传递
下面这段代码不会卡死,因为两个线程在彼此等待时完成了元素交接:
SynchronousQueuesq = new SynchronousQueue<>(); new Thread(() -> { try { sq.put("hello"); } catch (InterruptedException e) {} }).start(); new Thread(() -> { try { System.out.println(sq.take()); } catch (InterruptedException e) {} }).start(); // 输出:hello
但如果只调用 put 而没有对应 take,线程会一直阻塞;同理,只调用 take 也会阻塞。
基本上就这些 —— 它不是用来“增减元素”的队列,而是用来“促成一次原子*接”的同步工具。









