Reactor线程池切换publishOn与subscribeOn

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


🧠 一句话理解

  • **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 会影响:
    • 源数据的创建(如 fromCallable、Mono.just)
    • 源的订阅行为
    • 上游所有逻辑(在链条中靠前)

🧪 输出结果中的 log 会显示 Generating value 与 Mapping: 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 等),我可以针对场景详细分析。

相关推荐
宵时待雨11 天前
linux笔记归纳24:多路转接select
linux·服务器·笔记·高并发
ShineWinsu11 天前
对于Redis:Redis特性以及应用场景的解析
linux·c++·redis·缓存·高并发·分布式系统·key-value
底层玩家老张18 天前
什么是关系型数据库:一次库存超卖事故的内核复盘
高并发·mvcc·关系型数据库·存储引擎·acid
拒绝内耗。23 天前
高并发系统如何提升吞吐量?从扩容、缓存、异步到数据库优化
架构·高并发
凤山老林23 天前
高并发系统架构设计:Spring Boot 多级限流、库存预扣减与异步下单全链路实战
springboot·高并发·限流·异步
liulilittle25 天前
为什么采用全局管理缓存及状态:麻将客户端状态管理
服务器·网络·游戏·客户端·异步·mahjong·麻将
敲代码的嘎仔1 个月前
用 Redis 合并写 + DelayQueue 延迟检测,把视频播放进度写库频率降到 1/60
java·开发语言·数据库·redis·缓存·音视频·高并发
敲代码的嘎仔1 个月前
互动问答系统实战:两级评论模型、ES 搜索集成、Caffeine 多级缓存全记录
java·开发语言·数据库·elasticsearch·缓存·mybatis·高并发
隐擎fox1 个月前
高性能网络爬虫架构设计:基于 Python 的长连接复用与分布式会话池调度实践
分布式·python·网络协议·tcp/ip·高并发·网络爬虫、