Java里如何使用Exchanger实现数据交换_Java线程间交换机制解析

Exchanger 是 Java 中用于两个线程间成对同步交换数据的并发工具类,严格限制为两两配对、一次性原子交换,支持超时机制防止死锁,适用于双缓冲等双向协作场景。

Java 中的 Exchanger 是一个用于两个线程之间**成对同步交换数据**的并发工具类,适用于需要双向协作的场景(比如生产者-消费者配对、工作线程交换缓冲区等)。它不是“任意线程间广播”或“多线程共享”,而是严格限制为两个线程在屏障点等待并交换对象——一方调用 exchange() 阻塞,直到另一方也调用才完成交换。

Exchanger 的基本用法

创建 Exchanger 实例后,两个线程分别调用 exchange(V x) 方法传入自己的数据。该方法会阻塞当前线程,直到另一个线程也调用 exchange,然后双方原子性地交换对象并返回对方的数据。

  • 如果只有一个线程调用,它会一直等待(可设超时避免死锁)
  • 交换是一对一、一次性的:每次成功 exchange 后,Exchanger 可再次被复用,但必须仍是两两配对
  • 泛型参数 V 表示交换的数据类型,类型由使用者统一约定

典型使用场景示例

常见于双缓冲处理:线程 A 填充缓冲区 bufferA,线程 B 消费 bufferB;两者在某个时刻交换引用,实现无缝切换。

Exchanger exchanger = new Exchanger<>();
int[] myBuffer = new int[1024];

// 线程 A:填充后交换
myBuffer = exchanger.exchange(myBuffer); // 交出已填好的,拿到对方刚消费完的

// 线程 B:消费后交换  
myBuffer = exchanger.exchange(myBuffer); // 交出已消费完的,拿到对方刚填好的

注意:实际中需配合循环和状态控制,避免空指针或逻辑错位。

带超时的 exchange 更安全

为防止因某一方异常退出导致另一方永久阻塞,推荐使用带超时的重载方法:

  • exchange(V x, long timeout, TimeUnit unit)
  • 超时抛出 TimeoutException,可做清理或重试
  • 例如:exchanger.exchange(data, 3, TimeUnit.SECONDS)

注意事项与限制

Exchanger 不是万能的数据共享方案,使用前需确认是否符合其设计契约:

  • 只支持恰好两个线程参与一次交换;第三个线程调用会一直等待(无排队机制)
  • 不保证交换顺序,但保证成对发生;若线程中断,会抛

    InterruptedException
  • 内部基于 CAS 和自旋优化,性能较好,但不适合高频短数据交换(相比队列可能略重)
  • 不能替代 BlockingQueue、SynchronousQueue 等通用协调器,它是更专用的“镜像交换”原语

基本上就这些。Exchanger 简单但精准,用对了能写出清晰、低锁的双线程协作逻辑。