Exchanger 是 Java 并发包中专为两个线程设计的原子交换工具,通过“手拉手”配对机制实现对象引用的零拷贝、低延迟交换;必须严格双线程配对、禁止复用实例、交换前数据就绪、调用需设超时并处理中断与清理。

Exchanger 是 Java 并发包中专为两个线程设计的原子交换工具,它不靠锁、不靠队列,而是通过“手拉手”配对机制,在双方都到达时瞬间交换对象引用。用对了,零拷贝、低延迟;用错一个环节,就可能卡死线程或引发 NPE。
必须严格双线程配对,不能多也不能少
Exchanger 只认“当前阻塞的两个线程”,不记身份、不存历史。这意味着:
- 第三个线程调用 exchange() 会无限等待——前两轮已结束,槽位清空,无人响应
- 线程 A 异常退出(比如抛 RuntimeException),线程 B 就永远卡在 exchange() 上
- 在线程池中复用同一个 Exchanger 实例,无法保证“上一轮的 A 还在等 B”,协作链直接断裂
- 它不是 BlockingQueue 或 SynchronousQueue 的替代品,不支持多生产者或多消费者
交换动作要轻量,耗时逻辑必须移出来
exchange() 是同步屏障,不是执行入口。它的职责只是移交引用,不是干活:
- 先准备好数据(比如填满 buffer),再调用 exchange(buffer);不要在 exchange 内部边读边写或做序列化
- 避免在 exchange 中触发 GC 或长暂停,否则会拖慢配对线程,放大端到端延迟
- 典型做法是配合双缓冲(front/back)循环使用,exchange 就是切换控制权的开关,本身毫秒级完成
超时和中断必须主动兜底,不能忽略
无超时的 exchange(V) 在生产环境风险极高:
立即学习“Java免费学习笔记(深入)”;
- 务必用带参版本:exchange(x, 3, TimeUnit.SECONDS),超时后抛 TimeoutException,可降级、重试或释放资源
- 捕获 InterruptedException 后,必须恢复中断状态:Thread.currentThread().interrupt()
- 无论超时还是中断,都应触发清理:关闭临时资源、归还 buffer、上报监控指标
数据类型与对象生命周期要双方约定清楚
泛型只管编译期类型一致,运行时语义还得靠协作规范:
- 允许传 null,但若一方传 null、另一方直接 dereference,立刻 NPE——建议用哑值(如 new byte[0])或 Optional 封装
- 交换的是引用,不是副本。确保双方不共享同一对象实例,否则读写竞争仍需额外同步
- 收到对方 buffer 后,不要假设它“干净可用”:可能被对方复用、修改过,需按协议重置或校验


















