Exchanger 是 Java 并发包中专用于两个线程间同步交换数据的工具类,要求严格成对调用 exchange() 才能完成原子性对象互换,否则阻塞等待;支持泛型、可传 null、中断时抛 InterruptedException,适用于双缓冲、生产者-消费者配对等场景。

Exchanger 是 Java 并发包(java.util.concurrent)中一个专门用于两个线程间同步交换数据的工具类。它不像 BlockingQueue 或 SynchronousQueue 那样支持多线程协作,而是严格限定为成对线程配对交换——每次 exchange() 调用必须由两个线程同时到达才能完成,否则会阻塞等待。
Exchanger 的核心机制
Exchanger 本质是一个“交换点”:两个线程分别调用 exchange(V x) 方法,各自携带一个对象;当两个线程都到达时,它们携带的对象被原子性地互换,并各自拿到对方传来的值。若只有一个线程到达,它将一直阻塞,直到另一个线程也调用 exchange()。
- 只能用于恰好两个线程之间的配对交换,不支持 3 个及以上线程参与同一 Exchanger 实例
- 交换是同步阻塞的:线程 A 调用 exchange 后,必须等到线程 B 也调用 exchange 才能继续执行
- 支持泛型,类型安全;可传 null 值(但需双方约定好语义)
- 如果某一线程在等待时被中断,会抛出
InterruptedException
典型使用场景举例
常见于需要双缓冲处理或生产者-消费者成对协作的场景,比如:
- 图形渲染中,线程 A 渲染帧缓冲区 A,线程 B 渲染帧缓冲区 B,每帧结束时交换缓冲区指针供对方下一轮使用
- 数据采集与处理分离:采集线程填满一个数据块后,与处理线程交换该块,自己拿回一个空块继续采集
- 避免锁和额外队列开销,追求极简、确定性的双线程协同
基础代码示例
下面是一个模拟“数据块交换”的完整可运行示例:
立即学习“Java免费学习笔记(深入)”;
<font size="2"><pre class="brush:php;toolbar:false;">import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerExample {
static class Producer implements Runnable {
private final Exchanger<String> exchanger;
private String buffer = "empty";
Producer(Exchanger<String> ex) {
this.exchanger = ex;
}
@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
System.out.println("Producer: preparing data...");
buffer = "data-" + i;
System.out.println("Producer: ready to exchange [" + buffer + "]");
buffer = exchanger.exchange(buffer); // 等待 Consumer 并交换
System.out.println("Producer: got back [" + buffer + "]");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
static class Consumer implements Runnable {
private final Exchanger<String> exchanger;
private String buffer = "empty";
Consumer(Exchanger<String> ex) {
this.exchanger = ex;
}
@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
System.out.println("Consumer: ready to exchange, current buffer [" + buffer + "]");
buffer = exchanger.exchange(buffer); // 等待 Producer 并交换
System.out.println("Consumer: received [" + buffer + "]");
// 模拟处理耗时
Thread.sleep(100);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
Exchanger<String> ex = new Exchanger<>();
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new Producer(ex));
pool.submit(new Consumer(ex));
pool.shutdown();
}
}
运行时你会看到输出呈现明显的配对节奏:Producer 准备好后阻塞,Consumer 到达后立即交换,双方继续下一轮 —— 这正是 Exchanger 的“栅栏式同步”特性。
使用注意事项
- 确保只有两个线程使用同一个 Exchanger 实例;多个线程竞争会导致部分线程无限等待
- 注意超时控制:可使用
exchange(V x, long timeout, TimeUnit unit)避免永久阻塞(如网络异常、线程意外终止) - 交换前后建议校验数据有效性(例如非 null 判断),尤其在异常中断或超时后返回 null 时
- 不要在 exchange 调用中执行耗时操作,否则会拖慢配对线程,影响整体吞吐


















