SynchronousQueue的transfer方法核心是无缓冲直接交接:生产者与消费者在线程“碰头”时原子传递数据,依赖volatile Slot、CAS和park/unpark实现线程精确协作与唤醒。

SynchronousQueue 的 transfer 方法核心在于“无缓冲、直接交接”——它不存储元素,而是让生产者线程和消费者线程在同一个 Slot 上“碰头”,完成数据的原子传递。这个过程依赖 Slot 结构与线程状态的精确协调,本质是基于等待/唤醒机制的线程交替协作。
Slot 是什么:一个轻量级的同步协调点
Slot 不是队列节点,而是一个 volatile 字段(AtomicReference<Object>),充当临时中转站:
- 当消费者调用
take()时,若无生产者在等,它会把自己的线程对象(或 null 标记)写入 Slot,并阻塞等待; - 当生产者调用
put(x)时,发现 Slot 非空(即有等待的消费者),就直接把数据 x 写入 Slot,并唤醒对方; - 反之,若 Slot 为空,生产者把自己包装成
QNode(含数据和线程引用)写入,然后挂起。
transfer 如何实现线程交替:一次成功的“握手”流程
以 put(x) 遇到等待中的 take() 为例:
- 消费者已执行
slot.compareAndSet(null, this),将自身线程注册进 Slot,并调用LockSupport.park(this)挂起; - 生产者到达后,读取 Slot 发现是非 null 值(即消费者线程),于是执行
slot.compareAndSet(e, x)—— 把消费者线程替换成数据 x; - 紧接着调用
LockSupport.unpark(e)唤醒该消费者; - 消费者被唤醒后,检查 Slot 当前值:若已是数据 x,则取走并返回;若仍是自身线程(说明被中断或超时),则尝试 CAS 清空 Slot 并退出。
为什么需要 CAS + volatile + park/unpark 组合
这套机制靠三者协同保证正确性:
- volatile Slot 确保线程对 Slot 的读写对彼此可见,避免因缓存导致“看不见对方已到场”;
- CAS 操作 保证注册、替换、清理动作的原子性,防止两个生产者同时写入或两个消费者同时读取造成错乱;
- park/unpark 提供精准线程阻塞与唤醒能力,比 wait/notify 更可控,且不会因虚假唤醒破坏状态判断逻辑。
公平模式下的 TransferStack vs 非公平模式的 TransferQueue
SynchronousQueue 默认使用非公平策略(TransferQueue),但内部还有另一种实现:
- TransferQueue:基于 FIFO 的双向队列,新线程总在队尾入队,唤醒按先进先出顺序 —— 实际仍体现为“先到先得”的公平性;
-
TransferStack:用于公平模式(构造时传
true),采用 LIFO 栈结构,后到的线程优先匹配 —— 更倾向减少平均等待时间,但可能饿死早期线程; - 两者 transfer 主逻辑一致,差异仅在等待线程的组织方式与匹配顺序。

















