Exchanger详解

Exchanger 是 Java 并发工具类,用于 两个线程间双向交换数据 。线程通过 exchange() 方法阻塞等待配对,直到另一线程到达交换点并传递数据。适用于线程间协作交换结果的场景,如流水线处理或双向通信。

一、核心功能

  1. 数据交换:两个线程在同步点交换各自持有的数据。
  2. 线程阻塞 :调用 exchange() 的线程会阻塞,直到配对线程到达交换点。
  3. 双向传输:数据可双向传递,支持泛型定义交换对象类型。

二、核心方法

方法 说明
Exchanger() 构造方法
V exchange(V x) 阻塞当前线程,等待另一线程到达后交换数据
V exchange(V x, long timeout, TimeUnit unit) 带超时的交换,超时抛出 TimeoutException

三、典型使用场景

  1. 生产者-消费者协作 生产者与消费者交换缓冲区(如一个填充数据,另一个处理数据)。
  2. 流水线处理 多阶段任务中,前后环节线程交换中间结果。
  3. 双向通信协议 如网络通信中客户端与服务端交替发送和接收消息。

四、代码示例(数据交换)

typescript 复制代码
public class ExchangerDemo {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
​
        new Thread(() -> {
            try {
                String dataA = "数据A";
                System.out.println("线程1发送: " + dataA);
                String received = exchanger.exchange(dataA); // 阻塞等待交换
                System.out.println("线程1收到: " + received);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
​
        new Thread(() -> {
            try {
                String dataB = "数据B";
                Thread.sleep(1000); // 模拟处理延迟
                System.out.println("线程2发送: " + dataB);
                String received = exchanger.exchange(dataB);
                System.out.println("线程2收到: " + received);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

输出结果

less 复制代码
线程1发送: 数据A  
线程2发送: 数据B  
线程1收到: 数据B  
线程2收到: 数据A  

五、注意事项

  1. 仅限两个线程 超过两个线程调用 exchange() 会导致随机配对,可能引发混乱。
  2. 死锁风险 若配对线程未到达,或未调用 exchange(),当前线程会永久阻塞。
  3. 超时处理 使用带超时的 exchange() 避免无限等待,需捕获 TimeoutException
  4. 数据一致性 交换的对象需考虑线程安全,避免共享数据的并发修改问题。

六、对比其他工具

特性 Exchanger SynchronousQueue
数据方向 双向交换 单向传输
线程配对 严格两个线程 可多生产者和消费者
使用场景 协作交换数据 直接传递任务

七、高级用法

1. 缓冲区交换(生产者-消费者模型)

scss 复制代码
Exchanger<List<String>> exchanger = new Exchanger<>();
// 生产者填充缓冲区后交换
List<String> bufferA = new ArrayList<>();
new Thread(() -> {
    while (true) {
        fillBuffer(bufferA); // 生产数据
        bufferA = exchanger.exchange(bufferA); // 交换空缓冲区
    }
}).start();
​
// 消费者处理缓冲区数据
new Thread(() -> {
    List<String> bufferB = Collections.emptyList();
    while (true) {
        bufferB = exchanger.exchange(bufferB); // 交换填充后的缓冲区
        processBuffer(bufferB); // 消费数据
        bufferB.clear();
    }
}).start();

2. 超时与中断处理

kotlin 复制代码
try {
    String result = exchanger.exchange(data, 2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    System.out.println("交换超时,执行备用逻辑");
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // 恢复中断状态
    System.out.println("线程被中断");
}

总结Exchanger 是轻量级的线程间数据交换工具,适用于严格的两个线程协作场景。通过双向数据传递简化线程通信逻辑,但需注意线程配对和阻塞风险。在流水线处理或双向通信协议中表现优异,但在复杂多线程场景中应结合其他同步机制使用。

相关推荐
Dcs2 小时前
用不到 1000 行 Go 实现 BaaS,Pennybase 是怎么做到的?
java
Cyanto3 小时前
Spring注解IoC与JUnit整合实战
java·开发语言·spring·mybatis
qq_433888933 小时前
Junit多线程的坑
java·spring·junit
gadiaola4 小时前
【SSM面试篇】Spring、SpringMVC、SpringBoot、Mybatis高频八股汇总
java·spring boot·spring·面试·mybatis
写不出来就跑路4 小时前
WebClient与HTTPInterface远程调用对比
java·开发语言·后端·spring·springboot
Cyanto4 小时前
深入MyBatis:CRUD操作与高级查询实战
java·数据库·mybatis
麦兜*4 小时前
Spring Boot 集成Reactive Web 性能优化全栈技术方案,包含底层原理、压测方法论、参数调优
java·前端·spring boot·spring·spring cloud·性能优化·maven
天上掉下来个程小白4 小时前
MybatisPlus-06.核心功能-自定义SQL
java·spring boot·后端·sql·微服务·mybatisplus
知了一笑4 小时前
独立开发第二周:构建、执行、规划
java·前端·后端
今天背单词了吗9805 小时前
算法学习笔记:17.蒙特卡洛算法 ——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·笔记·考研·算法·蒙特卡洛算法