exchanger是专为两个线程严格配对交换数据设计的同步工具,不支持多线程、无缓冲、不记身份、不存历史,必须用带超时的exchange方法并确保交换动作轻量。

Exchanger 不是用来解决“多线程”协同的,而是专为两个线程严格配对交换数据设计的同步工具。它不支持三线程及以上协作,也不适合生产者-消费者模型中角色不对等、数量不固定的场景。用错场景,反而会引发永久阻塞或数据错配。
明确适用边界:只服务双线程配对
Exchanger 的本质是“手拉手”机制——它只认当前到达的两个线程,不记身份、不存历史、不缓存数据。一旦配对完成,交换槽位即清空。
- 第三个线程调用 exchange() 会无限等待,因为没有“第二个对手”来配对
- 若线程 A 异常退出,线程 B 在 exchange() 处挂起,整个协作链就卡死
- 在线程池中复用同一个 Exchanger 实例,无法保证“上一轮的 A 还在等 B”,协作关系必然断裂
交换动作必须轻量,别把耗时逻辑塞进去
exchange() 是同步点,不是执行点。它本身应瞬间完成,所有真正干活的事(如填充缓冲区、解析数据、写磁盘)必须放在 exchange() 调用前后。
- ✅ 正确做法:先填满 buffer,再调用 exchanger.exchange(buffer)
- ❌ 错误做法:在 exchange() 方法内部边读文件边构造对象
- 避免在 exchange() 中触发 GC 或长时间停顿,否则会拖慢配对线程,放大整体延迟
超时是生产环境的标配,不是可选项
无限等待的 exchange(V x) 只适用于测试或绝对可控的单机脚本。真实系统中,网络抖动、GC 暂停、线程调度延迟都可能导致配对失败。
- 始终优先使用 exchange(V x, long timeout, TimeUnit unit)
- 超时后抛出 TimeoutException,需捕获并做清理:释放 buffer、关闭句柄、上报监控指标
- 不要忽略 InterruptedException —— 捕获后务必调用 Thread.currentThread().interrupt() 恢复中断状态
数据类型与空值要双方提前约定好
泛型 T 保证编译期类型一致,但运行时语义仍需协作双方对齐。
- 允许传 null,但若一方传 null、另一方直接解包使用,会触发 NPE
- 建议用哑值替代 null,比如 new byte[0] 或 Optional.empty()
- 交换的是引用,不是内容。确保 frontBuffer 和 backBuffer 是两个独立对象,避免读写竞争











