Exchanger的核心作用是让两个线程在汇合点阻塞等待并安全交换对象引用,适用于双缓冲处理、批量数据交接等严格配对场景;必须恰好两个线程参与,推荐使用带超时的exchange方法以防死锁。

Exchanger 的核心作用与适用场景
Exchanger 是一个用于两个线程之间**成对同步交换数据**的并发工具类。它不是用来传递消息或共享状态,而是让两个线程在某个“汇合点”彼此等待,并安全地交换各自持有的对象引用。典型场景包括:双缓冲数据处理(如一个线程填充缓冲区A,另一个线程消费缓冲区B,然后双方交换)、生产者-消费者协作中批量数据交接、或者需要严格配对协作的并行计算任务。
基本使用方式:调用 exchange() 方法
每个线程调用 exchanger.exchange(data) 时会阻塞,直到另一个线程也调用该方法。一旦两个线程都到达,它们交换各自传入的对象,并同时返回对方的数据。注意:必须恰好两个线程参与;第三个线程调用会一直等待,除非有超时机制。
- 无参
exchange(V x):无限等待配对线程 - 带超时的
exchange(V x, long timeout, TimeUnit unit):避免死锁,推荐在生产环境使用 - 若等待超时,抛出
TimeoutException;若被中断,抛出InterruptedException
一个可运行的双缓冲交换示例
以下代码模拟两个线程交替填充与处理缓冲区:
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
<p>public class ExchangerExample {
static class Producer implements Runnable {
private final Exchanger<int[]> exchanger;
private int[] buffer = new int[10];</p><pre class="brush:php;toolbar:false;"> Producer(Exchanger<int[]> ex) { this.exchanger = ex; }
@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
// 填充当前缓冲区
for (int j = 0; j < buffer.length; j++) {
buffer[j] = i * 10 + j;
}
System.out.println("Producer: filled " + java.util.Arrays.toString(buffer));
// 与 Consumer 交换缓冲区
buffer = exchanger.exchange(buffer);
System.out.println("Producer: got back " + java.util.Arrays.toString(buffer));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
static class Consumer implements Runnable {
private final Exchanger<int[]> exchanger;
private int[] buffer = new int[10];
Consumer(Exchanger<int[]> ex) { this.exchanger = ex; }
@Override
public void run() {
try {
for (int i = 0; i < 3; i++) {
// 等待 Producer 交换来新数据
buffer = exchanger.exchange(buffer);
System.out.println("Consumer: received " + java.util.Arrays.toString(buffer));
// 模拟处理(清空)
java.util.Arrays.fill(buffer, 0);
System.out.println("Consumer: cleared to " + java.util.Arrays.toString(buffer));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
Exchanger<int[]> ex = new Exchanger<>();
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new Producer(ex));
pool.submit(new Consumer(ex));
pool.shutdown();
}}
立即学习“Java免费学习笔记(深入)”;
关键注意事项与最佳实践
Exchanger 不是通用通信机制,使用时需特别注意:
- 只支持严格两个线程配对,不适用于多线程广播或轮询场景
- 交换的是对象引用,不是深拷贝;若双方后续修改同一数组/集合,需自行保证线程安全
- 建议始终配合超时使用,防止因某一线程异常退出导致另一方永久挂起
- 可重复使用,每次
exchange()都是一次独立配对;无需重置或重建实例 - 内部基于 AQS 实现,性能高效,无明显锁开销



















