You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:29:52