Exchanger 是 Java 并发包中专为两个线程双向交换数据设计的同步工具,要求严格成对协作、无缓冲、原子安全,必须使用带超时的 exchange 方法并隔离实例以避免卡死与误用。

Exchanger 是 Java 并发包中专为两个线程间双向数据交换设计的同步工具,它不适用于多对多或一对多场景,而是严格面向“成对协作”——必须恰好两个线程参与一次交换,缺一不可。它的本质是一个阻塞式会合点,不是消息队列,也不是共享容器,而是一种轻量、原子、类型安全的配对机制。
Exchanger 的核心行为特征
调用 exchange(V x) 的线程会立即挂起,直到另一个线程也在同一 Exchanger 实例上调用 exchange()。此时两者才同时解阻塞,并互换数据:线程 A 得到线程 B 的 x,线程 B 得到线程 A 的 x。整个过程由 JVM 底层保证原子性与线程安全性,无需额外加锁或 volatile 修饰。
- 仅支持两两配对:第三个线程调用会无限等待,造成“卡死”,必须避免混用
- 泛型约束强制类型一致:声明
Exchanger<String>后,双方只能交换 String 类型数据 - 无内部缓冲区:不暂存历史数据,每次交换都是即时、一次性、不可重放的
- 默认非公平:谁先到达不一定先配对;如需顺序保障,可用
new Exchanger(true)启用公平模式
带超时的 exchange 防止死锁
生产环境严禁使用无参 exchange(V) —— 若一个线程异常退出或逻辑遗漏,另一线程将永久阻塞。推荐始终使用带超时的版本:
-
exchanger.exchange(data, 3, TimeUnit.SECONDS):3 秒内未配对则抛出TimeoutException - 捕获异常后应清理资源(如关闭连接、释放缓冲区)、记录日志,并决定是否重试或降级处理
- 超时值需结合业务耗时设定,不宜过短(频繁超时)也不宜过长(延迟暴露问题)
典型应用场景与实践要点
Exchanger 最自然的落点是双工流水线类任务,强调周期性、对称性、低延迟的数据协同:
-
双缓冲交换:生产者填满 bufferA 后调用
exchange(bufferA),消费者拿到 bufferA 同时把清空后的 bufferB 交还,双方无缝切换,避免读写冲突 - 校验/比对协作:线程 A 处理原始数据生成结果 R1,线程 B 独立处理同一输入得 R2,二者在 Exchanger 交换结果并比对一致性
- 游戏匹配/状态同步:两个玩家线程各自准备初始状态对象,通过 Exchanger 一次性交换并确认入场,避免状态错位
注意:不要试图用多个 Exchanger 实例模拟 N 线程轮转——逻辑复杂且易出错;若需多线程协调,请转向 CyclicBarrier 或 Phaser。
常见误用与规避方式
实际开发中容易踩的坑集中在生命周期和配对逻辑上:
- 同一个 Exchanger 实例被多个无关线程共用 → 必须按业务边界隔离实例,例如每个生产-消费对独享一个 Exchanger
- 线程未捕获
InterruptedException导致中断信号丢失 → 始终在 catch 块中调用Thread.currentThread().interrupt() - 交换前后未校验数据有效性(如 null、空集合)→ 在
exchange()返回后立即做非空与业务规则检查 - 在循环中反复 new Exchanger() → 实例本身无状态,可复用,应作为成员变量或单例注入
它不复杂,但要求你真正理解“配对”这个前提。用对了,代码简洁又健壮;用错了,问题往往静默且难定位。

















