我们当前正在从RxJava2迁移到Project Reactor。为了使工作并行化,我们通过Schedulers.newThread()
为每个并行HTTP请求创建一个新线程。我们无法重用线程,因为Spring的SecurityContext已绑定到ThreadLocal
。
最近,我们遇到了一个错误,那就是在一段时间后JVM遇到了OutOfMemory异常,因为未处理创建的线程导致了数千个驻留线程,而RxJava则是在成功的HTTP请求之后我们丢弃的线程。
对于RxJava,代码如下,在最后一行中有断点时,没有显示活动的附加线程。
Observable<String> deferred = Observable.fromCallable(() -> "1")
.subscribeOn(io.reactivex.schedulers.Schedulers.newThread());
Observable<String> deferred2 = Observable.fromCallable(() -> "2")
.subscribeOn(io.reactivex.schedulers.Schedulers.newThread());
System.out.println("obs: " + deferred.blockingSingle());
System.out.println("obs2: " + deferred2.blockingSingle());
但是对于Project Reactor,在两个标准输出之后,两个线程仍然处于活动状态。
Mono<String> mono1 = Mono.fromSupplier(() -> "1").subscribeOn(Schedulers.newSingle("single"));
Mono<String> mono2 = Mono.fromSupplier(() -> "1").subscribeOn(Schedulers.newSingle("single"));
System.out.println("Mono1: " + mono1.block());
System.out.println("Mono2: " + mono2.block());
为此,一种解决方案是在onFinally
中手动拆除调度程序:
Scheduler newSingle = Schedulers.newSingle("single");
Mono<String> doFinally = Mono.defer(() -> Mono.fromSupplier(() -> "1")).subscribeOn(newSingle).doFinally(s -> {
newSingle.dispose();
});
但是,这真的必要吗,还是有办法建立与RxJava2中相同的行为?