跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

SynchronousQueue 的 transfer:解析基于 Slot 的线程交替数据传递逻辑

SynchronousQueue的transfer方法核心是无缓冲直接交接:生产者与消费者在线程“碰头”时原子传递数据,依赖volatile Slot、CAS和park/unpark实现线程精确协作与唤醒。 SynchronousQueue 的 transfer 方法核心在于“无缓冲、直接交接”——它不存储元素,而是让生产者线程和消费者线程在同一个 Slot 上“碰头”,完成数据的原子传递。这个过程依赖 Slot 结构与线程状态的精确协调,本质是基于等待/唤醒机制的线程交替协作。 Slot 是什么:一个轻量级的同步协调点 Slot 不是队列节点,而是一个 volatile 字段(
AtomicReference ),充当临时中转站: 当消费者调用
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 主逻辑一致,差异仅在等待线程的组织方式与匹配顺序。

相关文章