Exchanger 是 Java 并发包中专为两个线程配对交换数据设计的同步工具,通过“手拉手”会合机制实现对象引用的原子交换,具备严格双线程配对、阻塞式同步点、零拷贝移交、类型与线程安全等核心特征。

Exchanger 是 Java 并发包中专为两个线程配对交换数据设计的同步工具,不靠锁、不依赖队列,而是通过“手拉手”式会合机制,在双方同时到达时完成内存引用的原子交换。它不是单向传递,而是双向移交——每个线程既送出一个对象,也即时拿到对方的对象。
Exchanger 的核心行为特征
理解它的运行逻辑,是正确使用的前提:
- 严格双线程配对:只支持且必须恰好两个线程参与;第三个线程调用 exchange() 会无限等待(除非超时),无法形成多路轮换
- 阻塞式同步点:任一线程先到 exchange() 就挂起,直到另一方抵达才触发交换;无缓冲、不排队、不缓存历史数据
- 零拷贝移交:交换的是对象引用,不是内容复制;适合大缓冲区复用(如图像处理中的 front/back buffer)
-
类型安全与线程安全内置:泛型
Exchanger<t></t>保证类型一致;内部基于 CAS + LockSupport 实现,无需额外同步
典型双线程协作模式
它最自然的用武之地,是存在周期性、对等性、交替性的数据流转场景:
- 双缓冲流水线:如渲染线程填满 backBuffer 后 exchange(backBuffer),处理线程正好完成上一轮,拿到该 buffer 开始解析,同时交出已处理完的 frontBuffer —— 两块内存循环复用,避免 GC 和竞争
- 镜像型生产-消费:生产者生成新数据后 exchange(),消费者交回上一轮处理结果;双方始终持有“自己刚产出、对方刚处理完”的数据,天然满足状态同步
- 协同校验或交叉计算:例如遗传算法中两个线程各自演化子种群,exchange() 后直接进行交叉操作;或风控系统中双模型并行打分,交换结果做一致性比对
带超时的健壮交换实践
在真实系统中,不能假设另一方总能准时抵达。使用带超时的 exchange(V, timeout, unit) 是必备习惯:
- 超时后抛出
TimeoutException,可触发降级逻辑(如重试、跳过、告警) - 若等待中被中断,则抛
InterruptedException,需恢复中断状态并退出 - 注意:超时返回前,Exchanger 会自动清理内部挂起节点,不泄漏资源
常见误用与规避建议
看似简单,但几个关键点容易引发问题:
- 不要把它当 BlockingQueue 用——没有容量、不支持多线程轮询、无法 peek 或 poll
- 避免在 exchange() 前后持有长临界区锁,否则会把“轻量同步”拖成“重量阻塞”
- 交换对象若含可变状态,确保双方不会同时修改同一实例(推荐交换不可变对象,或明确所有权移交语义)
- 日志或监控中建议记录 exchange 耗时分布,有助于识别配对延迟瓶颈(如某线程卡在上游计算)

















