上一篇分享了线程切换的一个操作符,今天我们继续分析线程切换的另一个操作符observeOn以及其源码设计。
observeOn操作符用于切换observer的线程:
Observable.create((ObservableOnSubscribe<String>) e -> {
e.onNext("dawson");
})
.observeOn(Schedulers.newThread())
.subscribe(s -> System.out.println("onnext value: " + s));
observeOn操作符需要传一个scheduler用于指定线程,并创建一个被观察者:ObservableObserveOn和一个观察者ObserveOnObserver。 ObservableObserveOn的source为上一个observable,最重的是其ObserveOnObserver,线程切换发生在该对象中。首先我们看看其subscribeActual的源码:
@Override
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
根据指定的scheduler获取其worker(上一篇文章已经分析了scheduler和worker的基本工作原理),并将worker和下游的observer传入到创建的ObserveOnObserver对象。下面看看ObserveOnObserver对象的onNext方法:
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
该方法不是直接调用下游的observer.onNext方法,而是将事件加入队列中,然后调用schedule()方法。Schedule方法会调用worker.schedule(this),然后回调run()方法,最后调用drainNormal()方法。而worker内部会使用指定的线程调用,那么drainNormal()即会在指定的新线程中执行。我们看看drainNormal()的部分源码:
void drainNormal() {
int missed = 1;
final SimpleQueue<T> q = queue;
final Observer<? super T> a = actual;
for (;;) {
//...
for (;;) {
boolean d = done;
T v;
try {
v = q.poll();
} catch (Throwable ex) {
//...
return;
}
//...
a.onNext(v);
}
//...
}
}
核心代码就是取出队列中的事件,然后调用下游的observer.onNext()方法将事件传递下去。由于该方法是在worker指定的新线程中执行,因此后面的observer处理逻辑都会在新线程执行,实现线程切换。在上一篇最后的流程图中加入observeOn,结合图进行分析和理解: