What is the difference between block() , subscribe() and subscribe(-)
Asked Answered
J

2

20
Mono.delay(Duration.ofMillis(10)).map(d -> {
            System.out.println(d);
            return d;
        }).block();

output : 0

Not able to see any output on console when I am calling with subscribe() or subscribe(-) methods instead of block()

Mono.delay(Duration.ofMillis(10)).map(d -> {
        System.out.println(d);
        return d;
    }).subscribe(System.out::println);

Do we need to use only doOnSubscribe(-) after this Mono.delay(-) method?

 Mono.delay(Duration.ofMillis(10)).doOnSubscribe(s -> {
        System.out.println("its printing doOnSubscribe");
    }).map(d -> {
        System.out.println(d);
        return d;
    }).subscribe(System.out::println);

output it's printing doOnSubscribe

Jin answered 6/1, 2020 at 5:39 Comment(0)
K
33

Your block() call explicitly holds the main thread until the publisher completes. By the time it's completed, it's executed the map() call, therefore printing the value.

Your subscribe() call on the other hand asynchronously executes the Mono on a separate scheduler, leaving your main thread to complete. Since the scheduler used by default uses daemon threads to execute your subscription, your program won't wait for it to complete before terminating.

If you introduce a delay long enough for the Mono to complete, you'll see the result you expect:

Mono.delay(Duration.ofMillis(10)).map(d -> {
    System.out.println(d);
    return d;
}).subscribe(System.out::println);

Thread.currentThread().sleep(500);

0 is then printed twice, once for the map() call and once by the System.out::println being used as a consumer.

In a real world use case you obviously won't just put in arbitrary sleep() calls - a CountDownLatch would be a more sensible choice:

CountDownLatch cdl = new CountDownLatch(1);
Mono.delay(Duration.ofMillis(10))
        .map(d -> {
            System.out.println(d);
            return d;
        })
        .doOnTerminate(() -> cdl.countDown())
        .subscribe(System.out::println);
cdl.await();
Kanchenjunga answered 6/1, 2020 at 10:33 Comment(4)
Thanks a lot @michael-berry. Its very useful for my requirement.Jin
In this case the CountDownLatch solution is equivalent to calling a simple block(), except that in the above code the error is lost unless we explicitly specify an error handler, in case of block() the error is automatically thrown by reactor.Provencher
Hi Michael, subscribe() will execute my code in which thread? I mean elastic/boundedElastic etc?Metalware
@MartinTarjányi In this specific case, I guess it is, indeed. But knowing about CountDownLatch was really helpful to me in a scenario where I have multiple subscriptions, and I needed to make sure all of them finished before continuing. And I couldn't just block, otherwise it would block on the first subscription before starting the other ones in parallel.Rondeau
W
1

To add what @MichaelBerry said in his excellent answer, and maybe to make it simpler:

The main difference is that subscribe() just "starts the whole computation" and doesn't wait (by contract) for its result. The computation may run in any other thread or even multiple threads. It may sometimes run only in the calling thread itself, which then looks like the same as block(). However, this is not by contract.

In contrast to block(), which by contract starts the computation and waits until it finishes.

You may also read my description here to understand why sometimes subsribe() and block() might give the same result.

Whinstone answered 19/2, 2024 at 22:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.