Spring reactor provides blocklast() if I want to be synchronous and block until all elements are done
But what if I want to continue a bit and then block until all elements are done?
( I do not want to perform a busy wait using isDisposed )
Do I need to do it myself with my own signal triggered by onComplete, or is there a better built in API?
//reactor provides blocklast if I want to be synchronous and block until all elements are done
//Integer data = Flux.range(1,10).delayElements(Duration.ofSeconds(1)).doOnNext((Integer next) -> System.out.println(next + " on thread " + Thread.currentThread().getName())).blockLast();
//but what if I want to continue a bit and then block
//do I need to do it myself like this? is there a better way?
Object signal = new Object();
Flux.range(1,10).delayElements(Duration.ofSeconds(1)).doOnNext((Integer next) -> System.out.println(next + " on thread " + Thread.currentThread().getName())).doOnComplete(()->{synchronized(signal) { signal.notify();}}).subscribe();
// do some other work here, then wait for done
synchronized (signal) {
signal.wait();
}
System.out.println("All done");
There is sadly no built-in API for this purpose, but there are better ways of doing this. Your Object.wait
will hang indefinitely if the Flux completes before you're done with your other work. You can solve this in multiple ways:
Here I create a second Publisher using Sinks.Empty
, who's only purpose is to emit an onComplete signal when the original Flux completes. We place the Sinks.Empty.emitEmpty()
trigger into the Flux.doOnComplete()
hook, then later block using .asMono().block()
. If you subscribe late, the Mono will complete immediately:
Sinks.Empty<Void> completionSink = Sinks.empty();
Flux.range(1,10)
.delayElements(Duration.ofSeconds(1))
.doOnNext((Integer next) -> System.out.println(next + " on thread " + Thread.currentThread().getName()))
.doOnComplete(() -> completionSink.emitEmpty(Sinks.EmitFailureHandler.FAIL_FAST))
.subscribe();
// do some other work here, then wait for done
completionSink.asMono().block();
System.out.println("All done");
Alternatively, you can put your other work in a second Publisher using Mono.fromRunnable
, then use Flux.merge
to subscribe to both Publishers simultaneously. Flux.merge
will emit all items from both Publishers and completes only if both are completed. Since your Mono.fromRunnable
does not emit any items, the resulting Flux will only contain the items of the original Flux.
Flux<Integer> flux = Flux.range(1, 10)
.delayElements(Duration.ofSeconds(1))
.doOnNext((Integer next) -> System.out.println(next + " on thread " + Thread.currentThread().getName()));
Mono<Void> otherWork = Mono.fromRunnable(() -> {
// do some other work here
});
Flux.merge(flux, otherWork).blockLast();
System.out.println("All done");
Note that Flux.merge
puts both Publishers onto the same Scheduler, which will cause problems if otherWork is not asynchronous or if the original Flux never completes. You can solve this by assigning different Schedulers to each Publisher.
I would simplify the answer of @Patrick Hooijer and use CountDownLatch
, this is perfect element of concurrent library, that waits while its value is changed to zero.
You just call.await() and its just awaits while the Flux call countDown
in doOnComplete
method.
CountDownLatch countDownLatch = new CountDownLatch(1);
Flux.range(1,10)
.delayElements(Duration.ofSeconds(1))
.doOnNext((Integer next) -> System.out.println(next + " on thread " + Thread.currentThread().getName()))
.doOnComplete(countDownLatch::countDown)
.subscribe();
countDownLatch.await();
System.out.println("All done");
There is sadly no built-in API for this purpose
This essential behaviour for me, thus we won't have to wait for any results if the main thread is getting to close, thus Flux could be a lot more time consuming than just throwing numbers, we would probably cannot close the main thread in this case.
But it depends on creators vision of that library, of course.
As I can see in your question, you want some other api to replace blockLast, right? And as far as I know, you have to implement this yourself. There is no built-in api for this purpose.
Mono.zip(
Mono.fromCallable(() -> {
//something
System.out.println("Completed doing");
return 1;
}).delaySubscription(Duration.ofSeconds(12)).subscribeOn(Schedulers.boundedElastic()),
Flux.range(1, 10)
.delayElements(Duration.ofSeconds(1))
.doOnNext((Integer next) -> System.out.println(next + " on thread " + Thread.currentThread().getName()))
.last()
)
.subscribe(__ -> System.out.println("All Done"));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.