exchanger 是 java 并发包中专为两个线程原子交换对象引用设计的同步工具,基于配对阻塞、cas 和 volatile 实现线程安全,需双方调用 exchange() 才完成交换,适用双缓冲、一对一流水线等低延迟场景。

Exchanger 是 Java 并发包中专为两个线程间原子交换对象设计的同步工具,不靠锁、不共享变量,靠“配对阻塞”实现天然线程安全。它不是消息队列,也不是通用通信通道,而是精准服务于“你给我数据,我给你数据”这一严格双向协作场景。
Exchanger 的核心交互逻辑
两个线程必须各自调用一次 exchange(V x),才能完成一次交换:一方传入自己的数据,挂起等待;另一方也调用后,双方立即互换引用并同时恢复执行。整个过程由 Exchanger 内部 CAS + volatile 机制保障原子性,无需额外同步。
- 单线程调用会永久阻塞(除非设超时),不存在“先到先得”或缓存行为
- 交换的是对象引用,不是深拷贝;若需隔离,应确保传入对象不可变或已克隆
- 类型 V 在编译期强约束,运行时允许 null 或不同实例,但语义需双方约定
保障数据安全的关键实践
安全不只靠类本身,更依赖使用方式。常见风险点集中在生命周期与异常处理:
- 总是优先选用带超时的
exchange(x, 3, TimeUnit.SECONDS),避免因线程异常退出导致对方无限等待 - 捕获
InterruptedException后必须调用Thread.currentThread().interrupt(),维持中断状态供上层感知 - 不要在动态线程池中复用同一个 Exchanger 实例——它不记录线程身份,无法保证“前一轮的 A 是否还在等 B”
- 若交换大对象(如 MB 级 byte[]),Exchanger 比 BlockingQueue 更高效,因其跳过队列操作,直接交换内存指针
典型高效应用场景
它在需要严格配对、低延迟、零拷贝的协作中优势明显:
- 双缓冲渲染:一个线程填充后台 buffer,另一个线程读取前台 buffer,exchange() 瞬间切换指针
- 生产者-消费者一对一流水线:生产者生成新数据块,消费者返回已处理完的旧块,形成闭环复用
- 协同计算任务:如分治算法中两子任务完成局部结果后,交换中间数据合并
一个不踩坑的最小可用示例
以下代码体现关键防护点:超时、中断恢复、明确职责分离:
Exchanger<string> ex = new Exchanger();
new Thread(() -> {
try {
String sent = "task-result-A";
String received = ex.exchange(sent, 2, TimeUnit.SECONDS);
System.out.println("A got: " + received);
} catch (TimeoutException e) {
System.err.println("A timed out waiting for partner");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 关键:恢复中断
}
}).start();
new Thread(() -> {
try {
String sent = "task-result-B";
String received = ex.exchange(sent, 2, TimeUnit.SECONDS);
System.out.println("B got: " + received);
} catch (TimeoutException e) {
System.err.println("B timed out waiting for partner");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
</string>
不复杂但容易忽略











