exchanger是java并发包中专为两个线程在同步点交换数据设计的协作工具,支持原子性配对交换,适用于分治算法、双缓冲处理等成对状态接力场景。

Exchanger 是 Java 并发包(java.util.concurrent)中一个轻量级的线程协作工具,适用于两个线程在某个同步点“交换”数据。它不用于通用的数据传递,而是在**成对协作、状态接力**的场景下非常高效——比如并行算法中,两个线程各自计算一部分中间结果,然后交换以继续后续处理。
Exchanger 的核心行为
它只支持两个线程配对交换:调用 exchange(V x) 的线程会阻塞,直到另一个线程也调用 exchange,二者原子性地交换对象引用。一旦配对成功,双方立即获得对方传入的对象,原地完成状态交接。
注意:它不是生产者-消费者模型,也不支持多于两个线程;若一个线程调用后长时间等不到配对,可能造成阻塞(可配合超时版本 exchange(V x, long timeout, TimeUnit unit) 防御)。
典型算法场景:分治型双线程迭代交换
例如实现一种双线程协同的迭代优化算法(如某些数值逼近、双缓冲图像处理、或并行归并中的中间合并阶段),每个线程维护局部状态(如当前最优解、局部直方图、临时数组),每轮计算后需交换状态以融合信息。
- 线程 A 计算子区间 [0, mid) 的中间统计值
stateA - 线程 B 计算子区间 [mid, n) 的中间统计值
stateB - 二者到达同步点,通过
exchanger.exchange(stateA)和exchanger.exchange(stateB)原子交换 - 交换后,A 拿到
stateB,B 拿到stateA,可基于对方结果做下一步聚合或修正
使用要点与避坑提示
实际编码中需注意几个关键细节:
- 状态对象应是可变且线程安全复用的:推荐复用对象(如重置内部字段),避免频繁创建;若不可变(如 Integer、String),交换后需重新构造新状态
- 配对必须严格成对:不能一个线程调用多次而另一线程只调用一次;建议用固定线程数(恰好 2 个)或通过任务调度确保配对逻辑清晰
-
异常处理要覆盖中断和超时:捕获
InterruptedException并恢复中断状态;超时返回 null 或特殊哨兵值,避免无限等待 - 避免在 exchange 调用中执行耗时操作:交换本身应快进快出;复杂逻辑放在交换前后,而非参数构造过程中
一个极简示例:双线程滚动最大值协同更新
假设有两个线程交替扫描数组片段,每轮结束后交换当前找到的最大值,使彼此能基于对方最新结果剪枝:
(伪代码示意,省略异常处理)Exchanger<integer> ex = new Exchanger();
// 线程1
Integer localMax = Integer.MIN_VALUE;
for (int i : part1) {
localMax = Math.max(localMax, i);
}
Integer peerMax = ex.exchange(localMax); // 等待线程2,拿到它的结果
if (peerMax > localMax) {
// 后续可基于 peerMax 做优化,比如跳过已知更小的区间
}</integer>
这种模式天然适合“乒乓式”协作,比用 BlockingQueue 或 AtomicReference 手动轮询更简洁、无锁且语义明确。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











