Exchanger 是 Java 并发包中专为两个线程同步交换数据设计的工具类,通过 exchange(V x) 实现一对一阻塞交换,适用于双工通信、数据比对等场景,Java 8+ 支持超时版本。

Exchanger 是 Java 并发包中专为两个线程之间同步交换数据设计的工具类,特别适合需要双向校对、配对处理的场景,比如双工通信、数据比对、协同计算等。它不适用于多于两个线程,也不支持超时或中断等待(Java 8+ 支持带超时的 exchange(V x, long timeout, TimeUnit unit)),但语义清晰、使用轻量。
Exchanger 的核心机制:成对阻塞交换
每个线程调用 exchange(V x) 时,会阻塞直到另一个线程也调用 exchange;两者交换各自传入的对象后同时返回。这天然形成“一对一握手”模型:
- 线程 A 调用
exchanger.exchange(dataA)→ 暂停等待 - 线程 B 调用
exchanger.exchange(dataB)→ 两者立即交换,A 得到dataB,B 得到dataA - 若只有一个线程调用,它将一直阻塞(除非使用带超时版本)
数据校对的典型实现模式
假设两个线程分别采集/生成同一业务实体的两份数据(如传感器 A/B 的读数、前后端独立计算结果),需在每次周期结束时比对一致性:
- 定义统一的数据载体类(如
Record),包含 ID、值、时间戳等关键字段 - 每个线程独立工作,完成后调用
exchanger.exchange(record) - 双方拿到对方数据后,执行校验逻辑(如数值差值、哈希一致、字段匹配)
- 校对结果可记录日志、触发告警或写入审计表,不影响主流程继续下一轮
一个简洁可用的校对示例
以下代码演示两个线程持续生成并校对随机整数:
立即学习“Java免费学习笔记(深入)”;
Exchanger<Integer> exchanger = new Exchanger<>();
Thread t1 = new Thread(() -> {
Random r = new Random();
for (int i = 0; i < 5; i++) {
int val1 = r.nextInt(100);
try {
int val2 = exchanger.exchange(val1); // 等待 t2 并交换
System.out.printf("T1: %d ↔ T2: %d → %s%n",
val1, val2, val1 == val2 ? "✓ match" : "✗ mismatch");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread t2 = new Thread(() -> {
Random r = new Random();
for (int i = 0; i < 5; i++) {
int val2 = r.nextInt(100);
try {
int val1 = exchanger.exchange(val2);
// 校对逻辑已在 t1 中体现,t2 可做对称检查或仅记录
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
t1.start(); t2.start();
使用注意事项与优化点
-
必须成对使用:确保两个线程确实都会调用
exchange(),否则一个线程永久阻塞 -
避免空值陷阱:如果允许
null作为有效数据,需额外约定;否则可用Objects.requireNonNull防御 - 超时控制更健壮:生产环境建议用带超时版本,防止因某线程异常退出导致另一方无限等待
- 校对失败不中断流程:把校对视为辅助能力,异常应捕获并记录,而非抛出中断主线程
-
类型安全优先:使用泛型明确交换类型(如
Exchanger<Report>),避免运行时类型错误


















