exchanger 的核心逻辑是“双向汇合、原子交换”——两个线程必须同时抵达同一实例的 exchange() 调用点才能完成零拷贝引用交换,成对阻塞、无缓冲、超时可配、天然适配双缓冲协作。

Exchanger 的核心逻辑是“双向汇合、原子交换”——两个线程必须同时抵达同一个 Exchanger 实例的 exchange() 调用点,才能完成一次安全的数据互换。它不依赖锁或队列,而是通过底层 CAS 和线程状态协调实现零拷贝引用交换,语义明确、开销极低。
成对阻塞:交换发生的前提条件
调用 exchanger.exchange(data) 的线程会立即挂起,进入 WAITING 状态,直到另一个线程也调用同一实例的该方法。两者不是“先后执行”,而是“必须同时到场”。若仅有一个线程调用,它将一直等待(除非设超时);三个及以上线程共用同一实例时,仅首两个能配对,其余持续阻塞。
- 没有“先来先服务”,只有“两人齐到才触发”
- 阻塞发生在用户态,不消耗 CPU 自旋
- 内部无缓冲区,不保存历史数据,内存占用恒定为两个对象引用
原子交换:数据移交的安全保障
一旦配对成功,Exchanger 在一个原子操作中完成两件事:把线程 A 的 data 交给线程 B,同时把线程 B 的 data 交给线程 A。整个过程不可中断、不可重排,且交换的是对象引用本身,不是副本——这对 byte[]、int[] 等大缓冲区尤其关键,避免了额外拷贝开销。
- 返回值永远是对方传入的对象,不是自己原来的 data
- 不会出现“一方已交出、另一方未收到”的中间态
- 泛型类型必须严格一致,否则编译失败或运行时报 ClassCastException
超时与异常:避免死等的关键设计
生产环境强烈建议使用带超时的重载方法 exchange(V x, long timeout, TimeUnit unit)。当协作线程因异常、阻塞或崩溃未能到达时,超时机制可及时释放当前线程,防止级联雪崩。
- 超时后抛出 TimeoutException,需捕获并做降级处理(如重试、日志告警、切换备用流程)
- 线程被中断时抛 InterruptedException,应恢复中断状态(Thread.currentThread().interrupt())
- 不推荐在构造时启用公平模式(new Exchanger(true)),虽能保证等待久者优先,但吞吐下降 10%~20%
典型协作模式:双缓冲与批量交接
Exchanger 天然适配“填满即交、用完即还”的闭环协作。例如图形渲染中,一个线程往 backBuffer 写像素,另一个线程从 frontBuffer 取帧显示;一轮结束后双方调用 exchange(),缓冲区角色即时翻转。
- 每次交换后,双方拿到的是对方刚处理完的数据,可直接复用
- 需配合循环逻辑使用,避免单次交换后流程中断
- 不适合异步通知、广播或多对一场景,那是 BlockingQueue 或 Phaser 的领域











