exchanger 是双向配对的原子交换机制,让生产者与消费者线程在同步点互相交换缓冲区引用,实现零拷贝的双缓冲轮转;要求严格双线程、类型一致、非空传参,并需处理中断与超时。

Exchanger 在生产者-消费者场景中不负责“搬运”数据,而是让两个线程在同步点**互相交换各自持有的数据对象引用**。它不是单向传递工具,而是双向、配对、原子性的交接机制——生产者交出填满的缓冲区,同时拿回一个空缓冲区;消费者交出处理完的结果或空容器,同时拿到待处理的新数据。
核心逻辑:一手交缓冲区,一手接空缓冲区
典型双缓冲模式下,生产者和消费者各持一块缓冲区(比如 List、byte[] 或自定义 Buffer 对象)。每次处理完成后,双方调用同一个 Exchanger 实例的 exchange() 方法:
- 生产者把装满数据的 bufferA 传入 exchange(),挂起等待
- 消费者把刚处理完、已清空(或初始为空)的 bufferB 传入 exchange(),双方瞬间交换引用
- 生产者拿到 bufferB,开始往里写新数据;消费者拿到 bufferA,开始读取并处理
这种设计天然避免了读写竞争——同一时刻,某块缓冲区只被一个线程持有,且角色明确(写入 or 消费),无需额外加锁或 volatile 控制可见性。
代码关键点:类型一致、空值防护、异常捕获
声明时需指定泛型类型(如 Exchanger>
),确保双方交换对象类型相同。实际使用中要注意:
- 不要传 null,否则另一方拿到 null 可能引发 NPE;建议初始化空集合或复用对象
- 必须捕获 InterruptedException;线程被中断时 exchange() 会抛出该异常,需重置中断状态或按需退出
- 不设超时的 exchange() 可能永久阻塞,若业务允许,可用 exchange(V x, long timeout, TimeUnit unit) 加保护
适用边界:严格双线程、节奏可对齐
这个模式成立的前提是:
- 只有且仅有两个协作线程参与交换(多于两个会无法配对,导致部分线程无限等待)
- 双方处理耗时相对均衡,避免一方长期空转、另一方频繁阻塞
- 没有外部生命周期干扰(比如 Kafka 消费线程因 rebalance 退出,就会让另一方卡死)
如果节奏差异大或线程不稳定,更适合用 BlockingQueue 或 SynchronousQueue 做单向接力。
不是搬运,是缓冲区轮转
Exchanger 不复制内容、不移动字节、不序列化传输,只是交换 Java 对象引用。整个过程零拷贝、低延迟,本质是协调两套内存资源的轮转使用权。它解决的是“谁在什么时候能安全写/读哪块内存”的协作问题,而不是“怎么把数据从 A 送到 B”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











