接上文Rxjava(一)——链式调用怎么实现的?
在分析线程切换原理前要明白几个概念;
线程调用的关键操作符subscribeOn、observeOn
observeOn作用:影响后续操作符所在的线程,直到下个observeOn设置为其他线程;
subscribeOn作用:初始化整个链条所在的线程,多次设置只有第一次生效;
线程调度器 Schedulers
Rxjava里面将常用线程归纳为4种,即有4 种调度器:
- 主线程 AndroidSchedulers.mainThread();
- io线程 Schedulers.io();
- 计算线程 Schedulers.computation();
- 新建线程 Schedulers.newThread();
同样以一个实例来进行分析:
Observable.just("a")
.observeOn(Schedulers.computation())
.map(new Func1() { //操作1
@Override
public String call(String s) {
System.out.print(Thread.currentThread().getName() + ":first--" + s +"\n");
return s + s;
}
})
.observeOn(Schedulers.io())
.map(new Func1() { //操作2
@Override
public String call(String s) {
System.out.print(Thread.currentThread().getName() + ":second--" + s+"\n");
return s + s;
}
})
.subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber() {//操作3
@Override
public void onCompleted() {
System.out.print(Thread.currentThread().getName()+"\n");
System.out.print("completed"+"\n");
}
@Override
public void onError(Throwable e) {
System.out.print("error");
}
@Override
public void onNext(String s) {
System.out.println(s);
}
});
上述实例中,分别使用了computation线程、io线程和新线程,执行代码如下:
由于subscribeOn是在整个调用链之前,其作用于整个链条,而observeOn只作用此它操作符之后,因此上图结束RxComputationThreadPool-1 在计算线程中,而之后的全部都处理io()线程RxCachedThreadScheduler-1中。
正式开始撸代码
带着几个问题来跟读代码:
- 1 Observable.just("a")生成的Observable对象,如何调用到计算线程中,线程切换通过什么实现的?
- 2 为什么subscribeOn()是对整个调用链条起作用?
问题1:Observable.just("a")生成的Observable对象,如何调用到计算线程中,线程切换通过什么实现的?
Observable.just("a").observeOn(Schedulers.computation())
由于just发送的单个对象,因此Observable使用的创建对象为ScalarSynchronousObservable;在其初始化对象时,将"a"作为构造参数传入,并保存。
observeOn操作符会首先对Observable的类型进行检测,若为ScalarSynchronousObservable类型,则通过ScalarSynchronousObservable@scalarScheduleOn来实现在某个线程中调度的过程;
跟进ScalarSynchronousObservable类,
public Observable scalarScheduleOn(Scheduler scheduler) {
if (scheduler instanceof EventLoopsScheduler) {
EventLoopsScheduler es = (EventLoopsScheduler) scheduler;
return create(new DirectScheduledEmission(es, t));
}
return create(new NormalScheduledEmission(scheduler, t));
}
很显然,使用DirectScheduledEmission,通过call,完成计算线程池的直接调度。
static final class DirectScheduledEmission implements OnSubscribe {
private final EventLoopsScheduler es;
private final T value;
DirectScheduledEmission(EventLoopsScheduler es, T value) {
this.es = es;
this.value = value;
}
@Override
public void call(final Subscriber super T> child) {
child.add(es.scheduleDirect(new ScalarSynchronousAction(child, value)));
}
}
//EventLoopsScheduler.class
public Subscription scheduleDirect(Action0 action) {
PoolWorker pw = pool.get().getEventLoop();
return pw.scheduleActual(action, -1, TimeUnit.NANOSECONDS);
}
public ScheduledAction scheduleActual(final Action0 action, long delayTime, TimeUnit unit) {
Action0 decoratedAction = schedulersHook.onSchedule(action);
ScheduledAction run = new ScheduledAction(decoratedAction);
Future> f;
if (delayTime <= 0) {
f = executor.submit(run);//执行动作
} else {
f = executor.schedule(run, delayTime, unit);
}
run.add(f);
return run;
}
到此时,executor.submit(run);执行,切换到对应线程上完成Action的调用;而Action里面做的什么事, 找到实现方法,发现其call()方法就是将数据传递到下一层去而已:
/** Action that emits a single value when called. */
static final class ScalarSynchronousAction implements Action0 {
private final Subscriber super T> subscriber;
private final T value;
private ScalarSynchronousAction(Subscriber super T> subscriber,
T value) {
this.subscriber = subscriber;
this.value = value;
}
@Override
public void call() {
try {
subscriber.onNext(value);
} catch (Throwable t) {
subscriber.onError(t);
return;
}
subscriber.onCompleted();
}
}
问题一到此,就分析得差不多了。
问题2: 为什么subscribeOn()是对整个调用链条起作用?
return nest().lift(new OperatorSubscribeOn(scheduler));
能对整个调用链起作用的关键点是nest();为什么这么说,看其实现;
public final Observable> nest() {
return just(this);
}
在此,可以看到其实还是使用的just,但是,关键是发送的观察者是this;发送this,就意味着subscribeOn所在的Observable对象发送了出去。this所代表的对象将会作为一个嵌套链表嵌入到subscribeOn所产生的新的Observable调用链中;
那么this如何嵌入到新的Observable中的呢?
查看OperatorSubscribeOn类源码,关键代码o.unsafeSubscribe。
@Override
public Subscriber super Observable> call(final Subscriber super T> subscriber) {
final Worker inner = scheduler.createWorker();
subscriber.add(inner);
return new Subscriber>(subscriber) {
@Override
public void onCompleted() {
// ignore because this is a nested Observable and we expect only 1 Observable emitted to onNext
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(final Observable o) {
inner.schedule(new Action0() {
@Override
public void call() {
final Thread t = Thread.currentThread();
o.unsafeSubscribe(new Subscriber(subscriber) {
@Override
public void onCompleted() {
subscriber.onCompleted();
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(T t) {
subscriber.onNext(t);
}
@Override
public void setProducer(final Producer producer) {
subscriber.setProducer(new Producer() {
@Override
public void request(final long n) {
if (Thread.currentThread() == t) {
// don't schedule if we're already on the thread (primarily for first setProducer call)
// see unit test 'testSetProducerSynchronousRequest' for more context on this
producer.request(n);
} else {
inner.schedule(new Action0() {
@Override
public void call() {
producer.request(n);
}
});
}
}
});
}
});
}
});
}
};
}
}
此处的o对象就是nest发送的this,通过unsafeSubscribe函数,重新形成调用链;
此处在执行的同时还存在线程切换,即inner.schedule。