Exchanger 的同步逻辑本质是“双线程碰头即换”——两个线程必须同时调用 exchange() 才能完成原子性数据移交,无中间存储、不依赖锁或队列,严格双向阻塞,缺一不可,超时与中断需显式处理,交换的是引用而非副本,类型安全需双方协同约定。

Exchanger 的同步逻辑本质是“双线程碰头即换”——没有中间存储、不依赖锁或队列,两个线程必须同时调用 exchange() 才能完成原子性数据移交。它不解决多线程协调问题,只专注把“配对协作”这件事做到极致:低延迟、零拷贝、语义明确。
严格双向阻塞,交换才发生
调用 exchanger.exchange(data) 的线程会立即挂起,直到另一个线程也调用同一实例的该方法。此时两者被唤醒,互换引用,各自拿到对方传来的对象后继续执行。
- 不是“先到先服务”,而是“两人必须同时到场”,缺一不可
- 单线程调用会永久等待(除非启用超时),第三个线程调用则陷入无效等待——因为前一对已清空状态,无人响应
- 不记录线程身份,也不保存历史配对关系,每次都是全新配对
交换动作必须轻量,避免拖慢配对方
exchange() 是同步点,不是执行点。耗时操作放里面,会直接拉长对方等待时间,破坏协作节奏。
- 缓冲区填充、序列化、网络IO、复杂计算等,一律放在
exchange()调用之前或之后 - 例如图像渲染场景:先填满
backBuffer,再调用exchanger.exchange(backBuffer)切换控制权 - 避免在
exchange()内触发 GC 或长时间停顿,否则端到端延迟明显升高
超时与中断必须显式处理
生产环境不能依赖“对方一定准时到达”。超时和中断不是异常分支,而是协作协议的正常组成部分。
- 优先使用带超时的重载:
exchange(data, 3, TimeUnit.SECONDS),超时抛TimeoutException,便于降级或重试 - 捕获
InterruptedException后,务必恢复中断状态:Thread.currentThread().interrupt() - 超时或中断发生时,应同步清理资源(如释放 buffer、关闭句柄、上报监控)
类型安全与对象生命周期需双方约定
泛型保证编译期类型一致,但运行时语义仍需协同设计。
- 交换的是引用,不是副本——双方不能共用同一缓冲区实例,否则读写竞争风险极高
- 允许传
null,但若一方依赖非空值,建议用哑值(如new byte[0])或封装为Optional - 交换返回的是对方数据,不是自己原值;常见错误是把
received当作本地处理结果继续使用


















