最近我写了一些复杂的基于RX的流程,并发现它总是在特定情况下产生死锁。我花了几个小时才发现出了什么问题,似乎可以通过这个简单的例子再现:
public static void main(String[] args) throws InterruptedException {
Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
.flatMap(x -> Observable.fromIterable(produceMultiple(x)))
.subscribeOn(Schedulers.computation())
.subscribe(System.out::println);
Thread.sleep(50_000);
}
private static List<Integer> produceMultiple(int x) {
return Observable.range(1, x)
.flatMap(y -> Observable.fromCallable(() -> {
Thread.sleep(1000);
return 10 * x + y;
}).subscribeOn(Schedulers.computation())
).toList().blockingGet();
}
此程序应打印以下值:11,21,22,31,32,33,...,99。通常,值可表示为XY。每个组X中的值的顺序可以是随机的,但组应按升序排序。如果先前仍在计算中,则不应该发出新组(这是我原来的情况)。
问题是,如果运行此代码,您将只看到前几个元素的输出 - 我相信它与处理器数量相关,因为calculate()调度程序使用固定的线程池大小。
你知道它为什么会这样吗?这似乎很奇怪,因为主链数(1,2,3,...)是在池中的单个线程上处理的,而每次使用blockingGet()完成其工作时,其他线程应该是空闲的。
如果你修改任何提供不同调度程序的subscribeOn()(或者一个是calculate()而第二个是不同的),一切正常。此外,如果我从自定义线程池执行器(绑定到4个线程)创建调度程序,它仍然有效!
答案 0 :(得分:0)
不要在blockingGet
调度程序上使用computation
,因为您可能会阻止代码其他部分使用的支持线程。您甚至不必在代码中使用它,只需从Observable
返回produceMultiple
:
static void main(String[] args) throws InterruptedException {
Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9)
.flatMap(x -> produceMultiple(x))
.subscribeOn(Schedulers.computation())
.subscribe(System.out::println);
Thread.sleep(50_000);
}
static Observable<Integer> produceMultiple(int x) {
return Observable.range(1, x)
.flatMap(y -> Observable.fromCallable(() -> {
Thread.sleep(1000);
return 10 * x + y;
}).subscribeOn(Schedulers.computation())
);
}