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

相关推荐
半夜修仙8 分钟前
RabbitMQ入门概述
java·rabbitmq·java-rabbitmq
fengxin_rou8 分钟前
【滑动窗口与前缀和算法实战】:LeetCode560.438 高频题深度解析
java·算法·leetcode
dusk_star10 分钟前
go语言--笔记--接口
java·笔记·golang
The Sheep 202313 分钟前
EFcore 查询数据
java·javascript
han_hanker18 分钟前
java8 stream 常用转换方法
java
星轨zb24 分钟前
从通用到专属:文迹(WenJi)引入 RAG 向量库的技术复盘
java·spring·langchain4j
我是一颗柠檬27 分钟前
【Java后端技术亮点】Feed流三级缓存设计,从10秒到100毫秒的优化实战
java·开发语言·后端·缓存
超梦dasgg32 分钟前
Java 正则表达式 完整详解(语法 + 核心类 + 常用方法 + 实战案例)
java·开发语言·正则表达式
码语智行33 分钟前
操作日志注解模块
java·前端·python
方也_arkling34 分钟前
【Java-Day17】API篇-BigInteger和BigDecimal
java·开发语言