Exchanger 是 Java 并发包中用于两个线程安全交换数据的协作工具,基于配对等待与原子交换机制,要求恰好两个线程参与,同步完成数据交换,支持泛型和超时控制。

Exchanger 是 Java 并发包(java.util.concurrent)中一个轻量级的线程间协作工具,专用于**两个线程之间安全地交换数据**。它不依赖锁或条件变量,而是基于等待/唤醒机制实现配对交换,适用于“成对协作”的典型场景(比如生产者-消费者模型中的缓冲区翻转、双缓冲计算等)。
核心原理:配对等待与原子交换
Exchanger 内部维护一个“交换槽”(slot),当第一个线程调用 exchange(V x) 时,它会尝试将数据放入槽中并等待另一个线程到来;第二个线程调用时,两者配对成功,原子性地交换数据并各自返回对方的数据。若超时或被中断,会抛出对应异常。
关键点:
- 必须恰好两个线程参与,第三个线程调用会一直阻塞(除非前两个已完成或超时)
- 交换是同步的:双方都到达后才同时返回,不存在“先到先得”或队列行为
- 支持泛型,类型安全;可指定超时时间避免无限等待
基本用法示例:双线程交换字符串
以下是一个清晰、可运行的最小示例:
立即学习“Java免费学习笔记(深入)”;
Exchanger<String> exchanger = new Exchanger<>();
Thread t1 = new Thread(() -> {
try {
String data = "来自线程1的数据";
String received = exchanger.exchange(data); // 阻塞直到t2也调用exchange
System.out.println("线程1收到:" + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread t2 = new Thread(() -> {
try {
String data = "来自线程2的数据";
String received = exchanger.exchange(data);
System.out.println("线程2收到:" + received);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
输出通常是:
线程1收到:来自线程2的数据 线程2收到:来自线程1的数据
实用场景与注意事项
常见适用场景包括:
- 双缓冲处理:一个线程填充缓冲区A,另一个线程消费缓冲区B;交换后角色互换
- 分阶段协同计算:如线程1生成中间结果,线程2基于该结果继续处理,再把新结果交还
- 测试线程交互逻辑:在单元测试中精确控制两个线程的数据流转时机
需注意:
- 如果只有一个线程调用
exchange(),它将永远阻塞(除非设了超时) - 不支持多个线程轮换交换(那是
CyclicBarrier或Phaser的职责) - 交换失败(如中断)时,当前线程抛出
InterruptedException,对方线程也会被唤醒并抛出BrokenBarrierException类似异常(实际为InterruptedException或TimeoutException)
带超时的健壮写法
生产环境建议始终设置超时,防止死锁风险:
try {
String received = exchanger.exchange(data, 3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.err.println("等待交换超时,可能另一方未启动或已异常退出");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
超时后当前线程继续执行,但交换未发生;对方线程若仍在等待,会继续阻塞,直到下次有线程配对或自身超时。


















