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

相关推荐
上海合宙LuatOS2 分钟前
LuatOS ——Modbus RTU 通信模式
java·linux·服务器·开发语言·网络·嵌入式硬件·物联网
野生技术架构师9 分钟前
Java 21虚拟线程 vs Kotlin协程:高并发编程模型的终极对决与选型思考
java·开发语言·kotlin
Vivienne_ChenW18 分钟前
DDD领域模型在项目中的实战
java·开发语言·后端·设计模式
Coder_Boy_18 分钟前
基于SpringAI的在线考试系统-整体架构优化设计方案(续)
java·数据库·人工智能·spring boot·架构·领域驱动
勤奋的小王同学~18 分钟前
SpringMVC
java·spring·mvc
笨蛋不要掉眼泪20 分钟前
RAG知识库核心API架构全解析:从文档加载到向量检索的完整流程
java·spring boot·redis·ai·架构
静谧空间34 分钟前
java登录验证码CaptchaConfig
java·开发语言
Imxyk38 分钟前
力扣:632. 最小区间(贪心)
java·数据结构·算法
驱动探索者40 分钟前
linux genpool 学习
java·linux·学习
露天赏雪41 分钟前
JDK8 的入门避坑指南
java·服务器·windows·spring boot·后端·spring·性能优化