在 Java 的 ja va.util.concurrent 包里,有一个不太起眼但非常实用的工具——Exchanger。它专门用于在两个线程之间交换数据,使用起来直观且高效。
可简单地将 Exchanger 对象理解为双格数据交换容器
它本质上是一个带有两个“格子”的容器。当线程调用 exchange() 方法时,会将数据放入其中一个格子。当两个格子都被填满后,Exchanger 会自动交换两个格子中的数据,并分别返回给对应的线程。这样,两个线程便完成了数据同步交换,整个过程是线程安全且同步的。
下面提供一段最简示例代码,帮助你快速上手 Exchanger 的使用:
package test;
import ja va.util.concurrent.Exchanger;
class ExchangerTest extends Thread {
private Exchanger exchanger;
private String string;
private String threadName;
public ExchangerTest(Exchanger exchanger, String string,
String threadName) {
this.exchanger = exchanger;
this.string = string;
this.threadName = threadName;
}
public void run() {
try {
System.out.println(threadName + ": " + exchanger.exchange(string));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
Exchanger exchanger = new Exchanger<>();
ExchangerTest test1 = new ExchangerTest(exchanger, "string1",
"thread-1");
ExchangerTest test2 = new ExchangerTest(exchanger, "string2",
"thread-2");
test1.start();
test2.start();
}
}
此示例程序创建了两个线程
每个线程在执行时都会调用同一个 Exchanger 对象的 exchange 方法,并传入自己的数据。当两个线程都成功将数据放入“格子”后,Exchanger 会自动交换数据并返回给各自线程。运行结果如下图所示:

需要特别注意的是,Exchanger 仅适用于两个线程之间的数据交换。如果有超过两个线程同时调用同一个 Exchanger 对象,交换结果将变得不可预测。这是因为 Exchanger 并不关心线程数量,它只关注两个“格子”是否被填满。一旦两个格子都满了,它就认为配对成功并立即执行交换——至于与哪个线程配对、剩余的线程如何处理,它一概不予理会。
不妨修改上面的示例,在第 33 行之后增加一个线程 test3,将其线程名设为 thread-3,交换字符串设为 string3:
ExchangerTest test3 = new ExchangerTest(exchanger, "string3","thread-3"); test3.start();
此时再运行程序,结果将变得不确定。多次测试可以发现,test1 可能和 test3 配对,也可能和 test2 配对。而那个未能配对的线程,由于没有成功配对,会一直阻塞在 exchange 方法上,陷入永久等待——除非你手动强制终止它。

总结与核心要点
Exchanger 的核心设计就是“一对二”的数据交换机制,其使用场景非常明确:当两个线程需要同步交换数据时,它是最简洁高效的解决方案。一旦线程数量超过两个,行为将变得不可控,未配对的线程会永久阻塞,因此在实际使用中务必按需控制线程数量。
