Exchanger 是 Java 并发包中用于两个线程间安全交换数据的同步工具,其核心是双向同步点,通过 CAS 和队列协调两线程配对交换,支持重复使用但仅限成对协作,不适用于多方场景。

Exchanger 是 Java 并发包(java.util.concurrent)中一个专门用于**两个线程之间安全交换数据**的同步工具。它不像 BlockingQueue 或 SynchronousQueue 那样支持多线程,而是严格设计为“成对”协作:两个线程调用 exchange() 方法后会相互等待,直到双方都到达交换点,然后原子性地交换各自携带的数据。
Exchanger 的核心机制
Exchanger 本质是一个**双向同步点**。它内部通过 CAS 和队列机制协调两个线程的到达顺序:
- 第一个调用
exchange(V x)的线程会阻塞,等待另一个线程也调用exchange(); - 第二个线程到来时,两者立即交换数据并返回 —— 整个过程是线程安全且不可中断的(除非被中断);
- 如果某个线程在等待时被中断,会抛出
InterruptedException,且不会完成交换; - 同一个 Exchanger 实例可重复使用,但每次成功交换只涉及两个线程(不支持三方或更多方)。
典型使用场景示例
常见于需要**双工流水线协作**的场景,比如:
- 生产者-消费者配对处理(如图像处理中,一个线程采集帧,另一个线程渲染帧,双方交换缓冲区);
- 乒乓缓冲(ping-pong buffer):两个线程轮流填充和消费同一组缓冲区;
- 测试或模拟双端交互逻辑(如网络协议中请求/响应线程配对)。
注意:它不适用于“一对多”或“广播”场景,也不替代 CountDownLatch 或 CyclicBarrier。
立即学习“Java免费学习笔记(深入)”;
基础用法与代码要点
声明一个 Exchanger<T> 实例,两个线程分别调用 exchange():
Exchanger<String> exchanger = new Exchanger<>();
Thread t1 = new Thread(() -> {
try {
String data = "from-t1";
String received = exchanger.exchange(data); // 阻塞,直到 t2 也调用 exchange
System.out.println("T1 received: " + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread t2 = new Thread(() -> {
try {
String data = "from-t2";
String received = exchanger.exchange(data);
System.out.println("T2 received: " + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start(); t2.start();
关键细节:
- 泛型类型必须一致,否则编译报错;
- 两个线程必须都调用
exchange()才能完成一次交换;若只有一个线程调用,它将一直阻塞(除非超时或中断); - 支持带超时的
exchange(V x, long timeout, TimeUnit unit),避免无限等待。
线程安全与异常处理建议
Exchanger 本身是线程安全的,无需额外同步。但需注意实际使用中的健壮性:
- 始终捕获
InterruptedException,并恢复中断状态(Thread.currentThread().interrupt()); - 避免在
exchange()调用前持有锁,否则可能引发死锁(因阻塞期间仍持锁); - 不要在交换对象中存放可变共享状态(如未同步的集合),交换后双方拿到的是同一对象引用,修改会影响对方;如需隔离,应在交换后复制或使用不可变对象。



















