Exchanger
是 Java 并发工具类,用于 两个线程间双向交换数据 。线程通过 exchange()
方法阻塞等待配对,直到另一线程到达交换点并传递数据。适用于线程间协作交换结果的场景,如流水线处理或双向通信。
一、核心功能
- 数据交换:两个线程在同步点交换各自持有的数据。
- 线程阻塞 :调用
exchange()
的线程会阻塞,直到配对线程到达交换点。 - 双向传输:数据可双向传递,支持泛型定义交换对象类型。
二、核心方法
方法 | 说明 |
---|---|
Exchanger() |
构造方法 |
V exchange(V x) |
阻塞当前线程,等待另一线程到达后交换数据 |
V exchange(V x, long timeout, TimeUnit unit) |
带超时的交换,超时抛出 TimeoutException |
三、典型使用场景
- 生产者-消费者协作 生产者与消费者交换缓冲区(如一个填充数据,另一个处理数据)。
- 流水线处理 多阶段任务中,前后环节线程交换中间结果。
- 双向通信协议 如网络通信中客户端与服务端交替发送和接收消息。
四、代码示例(数据交换)
typescript
public class ExchangerDemo {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
new Thread(() -> {
try {
String dataA = "数据A";
System.out.println("线程1发送: " + dataA);
String received = exchanger.exchange(dataA); // 阻塞等待交换
System.out.println("线程1收到: " + received);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
String dataB = "数据B";
Thread.sleep(1000); // 模拟处理延迟
System.out.println("线程2发送: " + dataB);
String received = exchanger.exchange(dataB);
System.out.println("线程2收到: " + received);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
输出结果:
less
线程1发送: 数据A
线程2发送: 数据B
线程1收到: 数据B
线程2收到: 数据A
五、注意事项
- 仅限两个线程 超过两个线程调用
exchange()
会导致随机配对,可能引发混乱。 - 死锁风险 若配对线程未到达,或未调用
exchange()
,当前线程会永久阻塞。 - 超时处理 使用带超时的
exchange()
避免无限等待,需捕获TimeoutException
。 - 数据一致性 交换的对象需考虑线程安全,避免共享数据的并发修改问题。
六、对比其他工具
特性 | Exchanger |
SynchronousQueue |
---|---|---|
数据方向 | 双向交换 | 单向传输 |
线程配对 | 严格两个线程 | 可多生产者和消费者 |
使用场景 | 协作交换数据 | 直接传递任务 |
七、高级用法
1. 缓冲区交换(生产者-消费者模型)
scss
Exchanger<List<String>> exchanger = new Exchanger<>();
// 生产者填充缓冲区后交换
List<String> bufferA = new ArrayList<>();
new Thread(() -> {
while (true) {
fillBuffer(bufferA); // 生产数据
bufferA = exchanger.exchange(bufferA); // 交换空缓冲区
}
}).start();
// 消费者处理缓冲区数据
new Thread(() -> {
List<String> bufferB = Collections.emptyList();
while (true) {
bufferB = exchanger.exchange(bufferB); // 交换填充后的缓冲区
processBuffer(bufferB); // 消费数据
bufferB.clear();
}
}).start();
2. 超时与中断处理
kotlin
try {
String result = exchanger.exchange(data, 2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("交换超时,执行备用逻辑");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
System.out.println("线程被中断");
}
总结 : Exchanger
是轻量级的线程间数据交换工具,适用于严格的两个线程协作场景。通过双向数据传递简化线程通信逻辑,但需注意线程配对和阻塞风险。在流水线处理或双向通信协议中表现优异,但在复杂多线程场景中应结合其他同步机制使用。