Reactor线程池切换publishOn与subscribeOn

在 Reactor(Project Reactor)中,publishOnsubscribeOn 是用于 切换执行线程(调度器) 的两个操作符,但它们的行为和用途 截然不同。下面是它们的详细区别与使用说明。


🧠 一句话理解

  • **subscribeOn**:指定源(Publisher)创建 & 订阅逻辑运行在哪个线程。
  • **publishOn**:指定后续操作符运行在哪个线程(从当前开始切换)。

🔁 subscribeOn:影响订阅动作及其"上游"

java 复制代码
Mono.fromCallable(() -> {
    log.info("Generating value");
    return "Hello";
})
.subscribeOn(Schedulers.boundedElastic()) // 👈 切换线程
.map(v -> {
    log.info("Mapping: {}", v);
    return v.toUpperCase();
});

📌 说明:

  • subscribeOn 会影响:
    • 源数据的创建(如 fromCallableMono.just
    • 源的订阅行为
    • 上游所有逻辑(在链条中靠前)

🧪 输出结果中的 log 会显示 Generating valueMapping: xxx 都在 boundedElastic 线程中执行。


🔀 publishOn:影响后续操作符

java 复制代码
Mono.fromCallable(() -> {
    log.info("Generating value");
    return "Hello";
})
.publishOn(Schedulers.parallel()) // 👈 从这里切换线程
.map(v -> {
    log.info("Mapping: {}", v);
    return v.toUpperCase();
});

📌 说明:

  • publishOn 只影响后续操作符的执行线程
  • 当前位置之后的操作符都在新的线程中执行
  • 当前位置之前的执行线程不会受影响

🧪 输出 log:

plain 复制代码
[main] Generating value
[parallel-1] Mapping: Hello

⚠️ 两者配合使用

java 复制代码
Mono.fromCallable(() -> {
    log.info("Generating value");
    return "Hello";
})
.subscribeOn(Schedulers.boundedElastic())
.publishOn(Schedulers.parallel())
.map(v -> {
    log.info("Mapping: {}", v);
    return v.toUpperCase();
});

🧪 输出 log:

plain 复制代码
[boundedElastic-1] Generating value
[parallel-1] Mapping: Hello

🔍 总结对比表

特性 subscribeOn publishOn
生效位置 整个流的最上游(首次调用生效) 只影响之后的操作符
常用于 指定数据源的线程(IO、慢操作) 指定数据处理的线程
多次调用 只有第一次调用有效(对源) 可以多次调用,影响每一处之后
应用场景 创建慢资源(数据库、文件等) 控制不同阶段逻辑在不同线程
替代线程切换逻辑 可以代替传统线程池包装异步逻辑 用于流中间切线程做不同的隔离或调度

✅ 实践建议

  • 网络/IO/阻塞调用 ➜ 放在 subscribeOn(Schedulers.boundedElastic())
  • 业务计算阶段 ➜ 用 publishOn(Schedulers.parallel()) 来提高并发度
  • 不要滥用这两个操作符,频繁切线程反而会增加上下文切换成本

如你有具体的使用场景(如 Flux + WebClient、文件读取、Kafka 等),我可以针对场景详细分析。

相关推荐
Thanks_ks6 小时前
分布式系统中的并发控制与分布式锁机制深度剖析
redis·zookeeper·高并发·分布式锁·架构设计·并发控制·分布式系统
猫吻鱼3 天前
【笔记03】【Reactor 响应式编程② - 事务编程】
笔记·reactor·webflux·jooq
YYYing.4 天前
【C++项目之高并发内存池 (二)】整体框架设计与ThreadCache的初步实现
笔记·高并发·线程池·c/c++
趣魂10 天前
五种并发/异步模型整理
并发·异步
逍遥德14 天前
Java 锁(线程间)和数据库锁(事务间)对比详解
java·数据库·sql·高并发·锁机制
如来神掌十八式14 天前
web高并发访问只能增加服务实例吗
高并发
Flying pigs~~16 天前
检索增强生成RAG项目tools_04:flask➕fastapi➕高并发
数据库·python·flask·大模型·fastapi·异步
qq_2837200517 天前
Python GIL 底层实现与高并发突破实战
python·性能优化·高并发·全局锁
切糕师学AI17 天前
深入浅出 协程(Coroutine):从原理到实践
高并发·协程·异步·async/await·coroutine·并发编程模型
2401_8920709818 天前
【Linux C++ 后端实战】异步日志系统 AsyncLogging 完整设计与源码解析
linux·c++·高并发·异步日志