exchanger的核心逻辑是两个线程必须同时调用exchange()才能完成对象引用的原子交换,不深拷贝、无缓冲、零排队;单线程调用将无限阻塞,需配对使用且推荐带超时版本以防卡死。

Exchanger 的核心逻辑是让两个线程在固定同步点“不见不散”地交换对象引用,实现零拷贝、无缓冲、原子性的状态切换——不是传递副本,而是直接移交内存地址,适合高频、低延迟的状态协同场景。
成对阻塞:必须两人同时到场才能触发切换
调用 exchange() 的线程会立即进入 WAITING 状态,不消耗 CPU,也不排队。它只等一个对象:另一个线程也调用同一 Exchanger 实例的 exchange()。没有“先来后到”,也没有队列缓存;第三个线程到来时,只会和前两个中尚未配对的那个配对,逻辑容易错乱。因此,必须确保只有且仅有两个活跃线程参与同一实例。
- 若仅一线程执行 exchange(),它将无限期等待(除非设超时)
- 线程生命周期需对齐:一方退出后,另一方再调用会永远卡住
- 常见做法是绑定固定线程对,避免线程池复用导致配对错位
原子交换:一次完成双向引用移交
配对成功瞬间,Exchanger 在一个不可中断的操作中完成两件事:把线程 A 的对象引用交给线程 B,同时把线程 B 的对象引用交给线程 A。交换的是引用本身,不是深拷贝——这对 byte[]、int[] 或封装状态的 POJO 尤其关键,省去序列化/复制开销。
- 返回值永远是对方传入的对象,不是自己原来的
- 不会出现“A 已交出但 B 还没收到”的中间态
- 泛型类型必须严格一致,否则运行时报 ClassCastException
超时与容错:避免系统因单点异常而卡死
生产环境严禁使用无参版 exchange(V)。必须采用带超时的重载方法,例如 exchange(data, 3, TimeUnit.SECONDS)。超时后抛出 TimeoutException,此时应主动中断当前周期、记录告警,并考虑降级策略(如复用上一周期状态)。
- 超时值需结合业务节拍设定:高频交易常用 5–20ms,离线批处理可设数秒
- 捕获 InterruptedException 后应恢复中断状态,并释放相关资源
- null 值虽合法,但易引发 NPE,建议业务层约定非空协议
典型状态切换模式:双缓冲与周期协同
最典型的落地方式是双缓冲循环:线程 A 填充缓冲区 A,线程 B 处理缓冲区 B;填满后双方调用 exchange(),A 拿到刚被消费完的 B 缓冲区继续填充,B 拿到刚填好的 A 缓冲区开始处理。整个过程无需锁、无额外内存分配,节奏由 exchange() 同步点自然驱动。
- 适用于订单簿快照交换、实时风控特征更新、音视频帧流转等场景
- 每个周期末尾交换,下一周期开始前双方已持有最新状态
- 避免在 exchange() 前后执行耗时操作,否则拖慢整体吞吐
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











