Mono.block()与Mono.subscribe()的区别及代码表现疑惑
Mono.block() 和 Mono.subscribe() 的真实区别
为什么你的测试里两者表现一致?
你用的Mono.just("test")是同步、立即完成的数据源,Reactor对于这种同步场景,会直接在订阅触发的线程上执行整个序列的操作(包括map),所以不管是block()还是subscribe(),当前线程都会先跑完map,再继续后续代码——这只是特殊场景下的巧合,不是它们的本质行为。
Mono.block() 的真实行为
- 核心是阻塞调用线程,直到Mono完成:调用
block()后,当前线程会暂停后续代码执行,直到Mono产生结果、抛出异常或超时。 - 你对“阻塞”的理解有误:阻塞不是指线程完全闲置,而是线程会等待整个Mono序列执行完毕。如果序列是同步的(比如
Mono.just),线程会直接在自身上执行map等操作,执行完再继续;如果是异步序列(比如远程调用、Mono.delay),线程才会真正进入等待状态,直到异步操作完成。
举个异步场景的例子,修改你的doBlocking():
void doBlocking() { final var myMono = Mono.delay(Duration.ofSeconds(1)) .map(elem -> { System.out.printf("On thread: [%s] inside map%n", Thread.currentThread().getName()); return "test"; }); String value; System.out.printf("On thread: [%s] before block%n", Thread.currentThread().getName()); value = myMono.block(); System.out.printf("On thread: [%s] after block%n", Thread.currentThread().getName()); System.out.println(value); }
输出会变成:
On thread: [main] before block // 这里main线程会阻塞1秒 On thread: [parallel-1] inside map On thread: [main] after block test
可以看到,main线程在block()处等待了1秒,map操作在Reactor的调度线程执行,这才是block()的典型阻塞表现。
Mono.subscribe() 的真实行为
- 核心是非阻塞触发订阅:调用
subscribe()后会立即返回,不会等待Mono完成,当前线程会继续执行后续代码。 - 同步数据源下的表现只是特例:因为
Mono.just会立即在当前线程执行map,所以看起来和block()一致;但换成异步数据源,就能看到本质区别。
修改你的doSubscribing()为异步场景:
void doSubscribing() { final var myMono = Mono.delay(Duration.ofSeconds(1)) .map(elem -> { System.out.printf("On thread: [%s] inside map%n", Thread.currentThread().getName()); return "test"; }); AtomicReference<String> value = new AtomicReference<>(); System.out.printf("On thread: [%s] before subscribe%n", Thread.currentThread().getName()); myMono.subscribe(value::set); System.out.printf("On thread: [%s] after subscribe%n", Thread.currentThread().getName()); System.out.println(value.get()); }
输出会变成你预期的样子:
On thread: [main] before subscribe On thread: [main] after subscribe null // 1秒后才会输出下面的内容 On thread: [parallel-1] inside map
这里main线程在subscribe()后直接继续执行,此时value还没被赋值,所以输出null;而map操作在1秒后由调度线程执行,之后value才会被设置为"test"。
核心区别总结
| 特性 | Mono.block() | Mono.subscribe() |
|---|---|---|
| 阻塞性 | 阻塞调用线程,直到Mono完成 | 非阻塞,调用后立即返回 |
| 结果获取 | 直接返回Mono的结果(或抛出异常) | 通过回调(Consumer)接收结果,无返回值 |
| 线程行为(异步场景) | 调用线程等待,操作在调度线程执行 | 调用线程继续执行,操作在调度线程执行 |
| 使用场景 | 适配传统阻塞代码(如main方法、测试) | 响应式代码核心,构建非阻塞流程 |
内容的提问来源于stack exchange,提问作者Dawid
相关产品推荐
相关产品推荐

