Exchanger 是 Java 并发包中用于两个线程间原子性交换数据的同步工具,需成对调用 exchange() 才能完成交换,适用于双缓冲、一对一协作等场景,不支持三线程及以上。

Exchanger 是 Java 并发包(java.util.concurrent)中一个轻量级的同步工具类,专用于**两个线程之间成对交换数据**。它不是用来传递消息或共享变量,而是让两个线程在某个“汇合点”各自携带一个对象,然后原子性地交换——双方同时交出自己的数据、拿到对方的数据。
核心机制:必须成对等待才能完成交换
Exchanger 的关键特性是“配对等待”。调用 exchange(V x) 方法的线程会阻塞,直到另一个线程也调用同一个 Exchanger 实例的 exchange() 方法。一旦两个线程都到达,它们交换值并同时返回;如果只有一个线程调用,它会一直等待(可设超时)。这天然避免了竞态和手动加锁的复杂性。
常见适用场景包括:双缓冲(如图形渲染中前后帧切换)、生产者-消费者协作(但仅限严格一对一)、算法中的协同计算(如分治任务结果合并)等。
基本使用方式:两线程各持一份数据,同步交换
以下是一个典型示例,模拟两个线程分别生成数据后交换:
Exchanger<string> exchanger = new Exchanger();
Thread t1 = new Thread(() -> {
String data1 = "from-thread-1";
try {
String received = exchanger.exchange(data1); // 阻塞,直到 t2 也调用 exchange
System.out.println("T1 sent: " + data1 + ", received: " + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread t2 = new Thread(() -> {
String data2 = "from-thread-2";
try {
String received = exchanger.exchange(data2);
System.out.println("T2 sent: " + data2 + ", received: " + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
</string>
输出类似:
T1 sent: from-thread-1, received: from-thread-2 T2 sent: from-thread-2, received: from-thread-1
注意事项与最佳实践
-
只能用于恰好两个线程:第三个线程调用
exchange()会无限等待(除非前两者已退出或中断),无法形成三元交换。 -
支持超时控制:使用
exchange(V x, long timeout, TimeUnit unit)可避免死等,适合有容错要求的场景。 - 线程中断会抛出 InterruptedException:务必正确处理中断状态(如恢复中断标志),否则可能破坏协作协议。
- 类型安全且无共享变量:交换过程由 Exchanger 内部同步保障,无需额外 volatile 或 synchronized,数据传递清晰可控。
- 不适用于高频短交换:相比无锁队列或 CAS 操作,Exchanger 有上下文切换开销;若只是频繁传递少量信号,考虑 CountDownLatch 或 Phaser 更合适。
异常情况处理建议
当某一线程提前终止(如抛异常、被中断),另一线程将长期阻塞。可通过以下方式增强鲁棒性:
- 为
exchange()设置合理超时,并在超时后主动清理资源或重试逻辑; - 确保线程生命周期可管理,例如使用 ExecutorService 启动,配合 shutdownNow() 中断所有待交换线程;
- 避免在 exchange 调用前持有其他锁,防止死锁(Exchanger 本身不持有外部锁,但业务逻辑可能引入依赖)。










