synchronousqueue 是无容量、不存储元素的同步移交队列,依赖生产者put()与消费者take()线程严格配对、瞬时交付,中间零缓存;适用于工作窃取、资源池交接等强同步场景。

SynchronousQueue 不是传统意义上的“队列”,它没有容量,不存储元素,只负责在生产者和消费者线程间建立直接、即时的握手交付。所谓“无缝交付”,本质是让一个线程的put()必须等待另一个线程同时执行take(),反之亦然——二者严格配对、瞬时完成,中间零延迟、零中转、零缓存。
理解它的核心机制:配对即交付
它内部不维护任何队列结构(无数组、无链表),所有操作都依赖线程阻塞与唤醒的精确协作:
-
put(e)调用后,当前线程立即挂起,直到有另一个线程恰好调用take();一旦匹配成功,元素直接从生产者线程栈传入消费者线程栈,不经过任何中间容器 -
take()同理:线程阻塞等待,直到有生产者调用put(),匹配后立刻获得元素 - 不支持
peek()、size()或迭代器——因为根本没有“待处理元素”的概念
典型适用场景:强制解耦 + 精确节拍
它不是为吞吐量设计的,而是为强同步控制服务:
- 工作窃取/任务委派:主线程生成一个任务,必须由某个空闲工作线程立即接手执行,不允许排队或丢弃
- 资源池交接:如数据库连接归还时,直接交到正在等待获取连接的线程手上,跳过连接池缓冲
-
双阶段协调流程:A线程完成准备后,必须等B线程就绪才开始下一步,用
put()/take()作为“就绪信号”载体
使用要点与避坑提示
看似简单,但误用会导致死锁或不可预期阻塞:
- 务必确保生产者和消费者线程数合理配比;单个生产者配多个消费者时,未匹配的
put()会永久阻塞,除非设超时(offer(e, timeout, unit)/poll(timeout, unit)) - 避免在同一线程中交替调用
put()和take()—— 它无法自匹配,会导致自己等自己 - 构造时可选公平模式(
new SynchronousQueue(true)):按 FIFO 顺序调度等待线程,避免某些线程长期饥饿;默认非公平,性能略高但调度不可预测 - 与
Executors.newCachedThreadPool()天然契合——该线程池底层正是用SynchronousQueue作为任务队列,实现“来活即建线程,无活即销毁”
一个极简示例:两个线程手递手传值
无需共享变量,不依赖锁,仅靠队列完成原子交接:
SynchronousQueue<string> sq = new SynchronousQueue();
Thread producer = new Thread(() -> {
try {
sq.put("Hello from producer");
System.out.println("Delivered");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread consumer = new Thread(() -> {
try {
String msg = sq.take();
System.out.println("Received: " + msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
// 输出顺序确定:先"Received: Hello from producer",再"Delivered"
</string>











