我们知道,subscribeOn() 方法通过接收一个 Scheduler 参数,来指定对数据的处理运行在特定的线程调度器 Scheduler 上。若多次执行 subscribeOn() 方法,则只有最初的一次起作用。
subscribeOn() 方法只有第一次调用才有效,需要满足以下条件:
被观察者必须是 Cold Observable。
被观察者多次调用 subscribeOn() 之后,并不意味着线程只会切换一次,而是线程多次切换之后,最终切换到第一次设置的线程。
所以, subscribeOn() 方法的调用并非一直有效。本文会通过列举一些事例,分析其失效的原因。
一. 创建 Observable 后内部使用了多线程发射数据
使用 RxJava 创建 Observable 后,假如内部使用了多线程发射数据,会带来什么影响呢?
RxJava 会通过 Scheduler、subscribeOn() 来管理线程,但只有在不手动更改线程的情况下,它才会这样做。
通常情况下,RxJava 发射的数据会在同一个线程上,但是稍作一些变化,发射的数据来自不同的线程会怎样呢?
public static void main(String[] args) {
Observable.create(emitter -> {
emitter.onNext(1);
new Thread("main") {
@Override
public void run() {
emitter.onNext(2);
emitter.onNext(3);
emitter.onNext(4);
emitter.onComplete();
}
}.start();
})
.subscribeOn(Schedulers.io())
.map(integer -> {
log(integer + " - I want this happen on an io thread");
return integer + "";
})
.subscribe(s -> log("Consume: "+s));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void log(String msg) {
System.out.println("Current Thread Name:"+Thread.currentThread().getName() + ", "+ msg);
}
执行结果:
Current Thread Name:RxCachedThreadScheduler-1, 1 - I want this happen on an io thread
Current Thread Name:RxCachedThreadScheduler-1, Consume: 1
Current Thread Name:main, 2 - I want this happen on an io thread
Current Thread Name:main, Consume: 2
Current Thread Name:main, 3 - I want this happen on an io thread
Current Thread Name:main, Consume: 3
Current Thread Name:main, 4 - I want this happen on an io thread
Current Thread Name:main, Consume: 4
上述执行结果表明,除了 emitter 发射的 1 是在 io 线程中执行的,其余的数字都是在 main 线程中运行的。
一旦 create 操作符中的 emitter 发射了数值,甚至在新的线程发射了值,RxJava 还是会很高兴地接受这些数值并将它们进一步传递给流。此时 RxJava 没有改变线程,是因为 subscribeOn() 方法已经完成了工作,订阅已经在其他线程上进行了。这时,没有理由 RxJava 会再次更改线程。所以,会看到上述的运行结果。
二. Hot Observable 对 subscribeOn() 调用造成的影响
2.1 特殊的创建操作符 just
just 是一个比较“特殊”的创建操作符,just 的作用是将单个数据转换为发射这个单个数据的 Observable。just 类似于 fromXXX,但是 fromXXX 会将数组或 Iterable 的数据取出然后逐个发射,而 just 只是简单地原样发射,将数组或 Iterable 当作单个数据。另外,just 创建的不是一个 Cold Observable。
下面以 just、fromCallable 为例:
public static void main(String[] args) {
System.out.println("from Just");
Observable justObservable = Observable.just(new Random().nextInt());
justObservable.subscribe(System.out::println);
justObservable.subscribe(System.out::println);
System.out.println("\nfrom Callable");
Observable callableObservable = Observable.fromCallable(() -> new Random().nextInt());
callableObservable.subscribe(System.out::println);
callableObservable.subscribe(System.out::println);
}
执行结果: