2

I'm learning Reactive programming with project-reactor.

I have the following test case:

@Test
public void createAFlux_just() {
    Flux<String> fruitFlux = Flux.just("apple", "orange");
    fruitFlux.subscribe(f -> {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(f);
    });
    System.out.println("hello main thread");
}

By executing the test it seems that the main thread is stuck for 5 seconds.

I would expect that the subscribed consumer should run asynchronously in its own thread, that is, the subscribe invoke should return immediately to the main thread and consequently the hello main thread should print instantly.

user711189
  • 4,383
  • 4
  • 30
  • 48

3 Answers3

2

The main thread is stuck because the subscription happens on the main thread. If you want it to run asynchronously, you need to the subscription to happen on a thread other than main. You could do this as:

 @Test
public void createAFlux_just() {
    Flux<String> fruitFlux = Flux.just("apple", "orange");
    fruitFlux.subscribeOn(Schedulers.parallel()).subscribe(f -> {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(f);
    });
    System.out.println("hello main thread");
}

Note: I have used the parallel thread pool. You could use whatever pool you like. Reactor's pipelines are executed on the calling thread by default (unlike CompletableFuture<T> which runs in the ForkJoin pool by default).

Prashant Pandey
  • 4,332
  • 3
  • 26
  • 44
1

This behavior would be the case if you had an observable (Flux) that was asynchronous. You chose to use a Flux with two readily available values by using the just method. They were passed to the subscription object right away since they were immediately available.

Sebastian
  • 5,177
  • 4
  • 30
  • 47
1

from spring.io documentation

The Threading Model Reactor operators generally are concurrent agnostic: they don’t impose a particular threading model and just run on the Thread on which their onNext method was invoked.

The Scheduler abstraction In Reactor, a Scheduler is an abstraction that gives the user control about threading. A Scheduler can spawn Worker which are conceptually Threads, but are not necessarily backed by a Thread (we’ll see an example of that later). A Scheduler also includes the notion of a clock, whereas the Worker is purely about scheduling tasks.

so you should subscribe on different thread by subscribeOn method and the Thread.sleep(5000) will sleep thread of the scheduler. You can see more examples like this one in the documentation.

Flux.just("hello")
    .doOnNext(v -> System.out.println("just " + Thread.currentThread().getName()))
    .publishOn(Scheduler.boundedElastic())
    .doOnNext(v -> System.out.println("publish " + Thread.currentThread().getName()))
    .delayElements(Duration.ofMillis(500))
    .subscribeOn(Schedulers.elastic())
    .subscribe(v -> System.out.println(v + " delayed " + Thread.currentThread().getName()));
Hakob Hakobyan
  • 1,111
  • 8
  • 15