exchanger 是 java 并发包中用于成对线程原子交换数据的同步工具,需严格两两配对、无缓冲、零拷贝,适用于生产者-消费者紧耦合场景,如双缓冲交换;误用易致死锁,应设超时、避免单线程自调用、注意对象所有权。

Exchanger 是 Java 并发包(java.util.concurrent)中一个轻量级的线程间同步工具,专为**成对线程交换数据**设计。它天然适合生产者-消费者场景中“一对一、对称协作”的需求,相比 BlockingQueue 或 wait/notify,更简洁、无中间缓冲、零内存拷贝开销。
Exchanger 的核心行为
两个线程调用 exchange(V data) 时会相互阻塞,直到双方都到达同步点,然后原子性地交换各自的数据并返回。若一个线程先到,它会等待另一个线程到来;超时或中断可被处理。
- 必须严格两两配对:每次 exchange 只涉及两个线程,多于两个线程调用会无限等待(除非主动超时)
- 无缓冲区:不保存历史数据,不支持“一对多”或“多对一”,适合流水线式接力或双工通信
- 类型安全:泛型参数确保交换数据类型一致,避免运行时转型错误
典型生产者-消费者结构(双线程配对)
适用于“一个生产者生成数据 → 一个消费者立即处理”的紧耦合场景,例如传感器采集与实时分析、网络请求与响应解析、双缓冲帧交换等。
- 生产者线程构造数据后调用
exchanger.exchange(buffer),挂起等待消费者就绪 - 消费者线程准备好接收容器后同样调用
exchanger.exchange(null)(或空缓冲),双方完成交换 - 交换后,生产者拿到刚被消费完的旧缓冲区(可复用),消费者拿到新数据——天然实现缓冲区循环利用
使用注意事项与避坑点
Exchanger 不是万能队列替代品,误用会导致死锁或吞吐下降:
- 避免在单线程内多次连续调用 exchange:这会造成自等待,永远无法配对
- 务必设置超时(
exchange(V, timeout, unit)):防止某一方异常退出后另一方永久阻塞 - 注意数据对象生命周期:交换的是引用,若生产者修改已交换出去的对象,可能引发竞态;建议交换不可变对象或明确所有权移交
- 不适用于异步批量处理:如需支持多个生产者/消费者,应选 BlockingQueue + 线程池,而非强行用多个 Exchanger 组合
一个最小可行示例
以下代码演示两个线程通过 Exchanger 交换 int 数组,模拟“填充”与“清空”协作:
Exchanger<int> ex = new Exchanger();
Thread producer = new Thread(() -> {
int[] buf = new int[1024];
for (int i = 0; i {
int[] buf = new int[1024];
for (int i = 0; i
</int>











