synchronousqueue 不支持 add() 和 offer(),因其无缓冲空间,仅用于线程间直接握手传递;put() 和 take() 阻塞等待配对操作,size() 恒为 0。

为什么 SynchronousQueue 不能直接 add() 或 offer()
它根本不是用来“存东西”的队列,而是为线程间**直接握手传递**设计的。调用 put() 的线程会一直阻塞,直到另一个线程正好在同时调用 take();反过来也一样。没有缓冲空间,所以 add() 和 offer() 永远返回 false(除非有配对线程正在等待)。
-
offer(e)立即返回false—— 因为没地方暂存 -
put(e)会挂起当前线程,直到有消费者来取 -
poll()立即返回null—— 因为没人刚放进来 -
take()会挂起当前线程,直到有生产者来放
SynchronousQueue 在 ThreadPoolExecutor 中的真实作用
它常被用作线程池的阻塞队列,比如 Executors.newCachedThreadPool() 内部就用了它。这时它的行为是:任务提交时若无空闲线程,就立刻创建新线程;而不是把任务排队等——这和你直觉里的“队列”完全相反。
- 搭配
corePoolSize=0+maximumPoolSize=MAX_VALUE才能发挥效果 - 任务不会堆积,但线程可能无限增长(注意 OOM 风险)
- 不适合高吞吐、低延迟敏感场景,因为每次任务交接都涉及线程唤醒开销
用错 SynchronousQueue 的典型错误现象
最常见的是程序卡死或线程永远阻塞,尤其在单线程环境或未配对调用时。
- 只调
put("x")不调take()→ 生产者线程永久 WAITING - 只调
take()不调put()→ 消费者线程永久 WAITING - 在同一个线程里先
put()再take()→ 必死锁(自己等自己) - 用
size()判断是否为空 → 总是返回0,毫无意义
替代方案选型:什么时候不该用 SynchronousQueue
它只适合明确需要“点对点即时交接”的场景。一旦你需要缓冲、重试、批量处理或异步解耦,它就成累赘了。
立即学习“Java免费学习笔记(深入)”;
- 要积压任务?换
LinkedBlockingQueue或ArrayBlockingQueue - 要控制并发数?用
Semaphore配合普通队列更直观 - 要做背压或流控?
TransferQueue子类如LinkedTransferQueue更灵活 - 测试时想绕过阻塞?别硬等,改用带超时的
poll(1, TimeUnit.SECONDS)或换队列
它的特别之处不在容量为零,而在于强制要求“同步协作”——这个契约一旦被打破,就只剩阻塞和死锁。








