为何publishOn()会影响前置Mono.fromRunnable()的执行线程?
为什么publishOn()会影响Mono.fromRunnable()的执行线程?
测试代码
Mono.fromRunnable(() -> log.info("Thread {}", Thread.currentThread().getName())) .publishOn(Schedulers.boundedElastic()) .subscribe();
日志输出
Thread boundedElastic-<x>
更换调度器时,线程名称会对应变化,这并非偶然。核心疑问是:为什么publishOn()调度器会影响Mono.fromRunnable()中lambda表达式的执行线程?
按照Reactor文档的描述,publishOn()本应仅影响下游操作,比如下面这个符合预期的示例:
对比示例代码
Mono.just("x") .doOnNext(_w -> log.info("Thread before {}", Thread.currentThread().getName())) .publishOn(Schedulers.boundedElastic()) .doOnNext(_w -> log.info("Thread after {}", Thread.currentThread().getName())) .subscribe();
对应日志输出
Thread before Test worker Thread after boundedElastic-<x>
原因解析
问题的核心在于Mono.fromRunnable的延迟执行特性:
fromRunnable不会立刻执行传入的任务,而是将其封装为一个“懒加载”的数据源——只有当订阅发生时,这个Runnable才会被触发执行。publishOn的作用是指定订阅后整个数据流的执行上下文,包括上游那些延迟执行的任务逻辑。
在第一个测试代码中,调用subscribe()时,整个数据流的执行会切换到publishOn指定的boundedElastic调度器线程池,fromRunnable里的任务自然就在该线程中执行,所以日志显示的是调度器线程名称。
而在对比示例中,Mono.just("x")是已就绪的数据源(创建时就生成了数据),publishOn之前的doOnNext会在订阅线程(这里是Test worker)上执行;publishOn之后的下游操作才会切换到指定调度器线程,这就是我们对publishOn“仅影响下游”的常规认知场景。
总结
- 对于延迟执行的上游数据源(如
fromRunnable、fromCallable),publishOn会影响其执行线程,因为它们的触发时机在订阅阶段,此时上下文已被调度器接管。 - 对于已就绪的上游数据源(如
just、from),publishOn仅会切换其下游操作的执行线程,上游逻辑不受影响。
内容的提问来源于stack exchange,提问作者rosik
相关产品推荐
相关产品推荐

