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

相关推荐
zdl68621 分钟前
Spring Boot文件上传
java·spring boot·后端
世界哪有真情23 分钟前
哇!绝了!原来这么简单!我的 Java 项目代码终于被 “拯救” 了!
java·后端
RMB Player25 分钟前
Spring Boot 集成飞书推送超详细教程:文本消息、签名校验、封装工具类一篇搞定
java·网络·spring boot·后端·spring·飞书
重庆小透明30 分钟前
【搞定面试之mysql】第三篇 mysql的锁
java·后端·mysql·面试·职场和发展
RuoyiOffice38 分钟前
企业请假销假系统设计实战:一张表、一套流程、两段生命周期——BPM节点驱动的表单变形术
java·spring·uni-app·vue·产品运营·ruoyi·anti-design-vue
鹤旗39 分钟前
While语句,do-while语句,for语句
java·jvm·算法
小碗羊肉1 小时前
【从零开始学Java | 第十八篇】BigInteger
java·开发语言·新手入门
sky wide1 小时前
[特殊字符] Docker Swarm 集群搭建指南
java·docker·容器
wuqingshun3141591 小时前
谈谈你对springAop动态代理的理解?
java·jvm
执笔画流年呀1 小时前
PriorityQueue(堆)续集
java·开发语言