exchanger 是 java 中专为两个线程设计的零拷贝双向交换工具,必须严格成对使用、独占实例、校验数据、设置超时、避免重操作。

Exchanger 是 Java 并发包中专为两个线程设计的双向数据交换工具,它不靠锁、不依赖队列,而是通过“手拉手”式配对等待,实现零拷贝、原子性的即时交换。用对了,性能高、逻辑清;用错了,线程卡死、数据错乱。
必须严格成对,一个都不能多或少
Exchanger 只服务两个线程:A 等 B,B 等 A。第三个线程调用 exchange(),它会无限等待——因为没有配对者,不是排队,是“一对一握手”。
- 别在线程池里复用同一个 Exchanger 实例,不同任务组应各自持有独立实例
- 避免动态增减协作线程,比如某线程异常退出后,另一方仍在死等,建议配合生命周期管理(如 try-finally 中确保清理或通知)
- 生产环境推荐每个双线程协作单元(如一对图像处理线程)独占一个 Exchanger 实例
交换时机要卡在数据真正就绪之后
exchange() 不是启动信号,而是交付动作。提前调用等于交出空包或脏数据。
- 写完 buffer 再 exchange,而不是 new 出 buffer 就立刻交换
- 接收方拿到对象后应做基础校验:非 null、字段完整、格式合法,不能默认对方一定给对了
- 预处理和后处理逻辑要放在 exchange() 前后,而非塞进参数构造或返回值解析里
超时不是可选配置,是生产必备防护
无超时的 exchange(V) 一旦卡住(GC 暂停、IO 阻塞、逻辑 bug),整个协作流程就僵死。
- 强制使用 exchange(V, timeout, unit),3 秒是多数流水线场景较稳妥的起点
- 捕获 TimeoutException 后要有明确降级策略:跳过本轮、重试、记录告警,不能只打日志
- 同时处理 InterruptedException,并恢复中断状态 Thread.currentThread().interrupt()
别在 exchange() 里干重活
exchange() 本身应是瞬时操作。耗时计算、复杂解析、网络请求都该挪到 exchange() 调用之外。
- 例如双缓冲图像处理:A 完成 bufferA 处理 → 立即 exchange(bufferA) → 紧接着开始处理 bufferB
- 如果在 exchange() 前做了 200ms 的序列化,那 B 线程也在等这 200ms 才能继续,放大整体延迟
- 大对象交换本身很快(只是引用交换),但构造或消费环节拖慢,会破坏协作节奏











