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

相关推荐
不当菜虚困7 分钟前
JAVA设计模式——(九)工厂模式
java·开发语言·设计模式
暖苏8 分钟前
Spring中bean的生命周期(笔记)
java·spring boot·spring·spring cloud·mvc·bean生命周期·springbean
IT技术员12 分钟前
【Java学习】Java的CGLIB动态代理:通俗解释与使用指南
java·开发语言·学习
IvanCodes22 分钟前
Java 基础--流程控制语句
java·开发语言
caimouse30 分钟前
C#里创建一个TCP客户端连接类
java·网络·tcp/ip
Sunniering33 分钟前
Springboot整合阿里云腾讯云发送短信验证码 可随时切换短信运营商
java·阿里云·云计算·腾讯云·springboot·短信
caihuayuan534 分钟前
IOS 国际化词条 Python3 脚本
java·大数据·spring boot·后端·课程设计
wjm0410061 小时前
C++日更八股--first
java·开发语言·c++
wei3872452321 小时前
java练习2
java·开发语言·python
heyCHEEMS2 小时前
[USACO09OCT] Bessie‘s Weight Problem G Java
java·开发语言·算法