transferqueue 是接口,linkedtransferqueue 是其无界、支持“匹配传递+入队”双模式的实现;synchronousqueue 是零容量、必须严格配对阻塞的队列。

TransferQueue 是什么?它和 SynchronousQueue 的根本区别在哪
TransferQueue 不是一个具体类,而是一个接口;LinkedTransferQueue 是它的标准实现。它比 SynchronousQueue 更灵活:既能像普通阻塞队列一样存数据(无界、CAS 无锁),也能像 SynchronousQueue 那样“手递手”直接传递——关键在于你调用哪个方法。
SynchronousQueue 根本不存数据:put() 必须等到另一个线程执行 take() 才返回;没匹配就一直卡住。而 LinkedTransferQueue 默认会先尝试匹配等待的消费者,匹配不上就直接入队(异步入队),不会阻塞生产者。
-
SynchronousQueue:零容量,“传球必须有人接”,否则传球者原地冻结 -
LinkedTransferQueue:无限容量,“先找人接,没人接就先放旁边货架上”,生产者不卡死 - 公平性上:
SynchronousQueue可设公平模式(FIFO 等待),但LinkedTransferQueue本身不提供公平开关——它的匹配逻辑天然偏向“就近唤醒”,实际表现接近公平
什么时候该用 transfer()?它和 put()、offer() 的行为差异
如果你需要确保一个任务“立刻被消费”,而不是“先进队列再等消费”,那就该用 transfer()。它会阻塞直到有消费者 take() 或 poll() 到这个元素——这建立了明确的 happens-before 关系,适合强一致性场景(比如状态同步、事件确认)。
-
transfer(e):必须匹配成功才返回;若当前有等待消费者,立刻交付;否则阻塞等待 -
put(e):总是成功(因为队列无界),不保证谁消费、何时消费 -
offer(e):非阻塞,立即返回 true;不关心有没有消费者 -
tryTransfer(e, timeout, unit):带超时的“尽力传递”,超时未匹配则返回 false,适合防雪崩
示例:发送一条“订单已创建”事件,下游必须立刻处理并返回 ACK,这时用 transfer(event) 比 offer(event) 更稳妥。
为什么 hasWaitingConsumer() 和 getWaitingConsumerCount() 很实用
这两个方法是 TransferQueue 独有、SynchronousQueue 完全没有的能力。它们让你能“看一眼”当前有没有消费者在排队等着拿数据——这对动态扩缩容、负载预判、熔断降级非常关键。
-
hasWaitingConsumer()返回 boolean,开销极小,适合高频探测(如每秒检查是否需启动备用消费者) -
getWaitingConsumerCount()返回整数,可用于统计或触发阈值告警(比如 >50 就自动扩容消费者实例) - 注意:这两个值是瞬态快照,不能用于条件竞争判断(比如“if (hasWaitingConsumer()) then transfer()”仍可能失败)
踩坑提醒:别把 LinkedTransferQueue 当成 ConcurrentLinkedQueue 用
它虽然底层也是 CAS 链表,但设计目标完全不同:ConcurrentLinkedQueue 是纯非阻塞、无等待语义的队列;而 LinkedTransferQueue 的核心价值恰恰在于“可阻塞 + 可匹配”。如果你只调 offer() 和 poll(),等于白用了它的传输能力,还多承担了匹配逻辑的微小开销。
- 误用场景:用
offer()生产 +poll()消费,且从不调transfer()或检查等待消费者——此时不如直接用ConcurrentLinkedQueue - 内存风险:它是无界队列,如果消费者持续慢于生产者,
offer()会不断堆积,最终 OOM(这点比有界的ArrayBlockingQueue更危险) - 调试难点:JVM dump 中看到大量
QNode(内部节点)且isData==false,说明一堆消费者在take()后挂起等待——得查下游是不是卡死了
真正发挥 TransferQueue 价值的地方,是那些“传递即承诺”的环节:不是把活儿扔进池子就完事,而是要确认对方已经伸手接住。










