本来是想说说RxJava之转换器的,但是发现,如果不来讲讲Rx的Schedulers,好像总感觉少了点什么。因为RxJava让我们用的最爽的地方,莫过于这一块了。我们可以随意的进行线程切换,是那么的简洁优美,尤其是配合RxAndroid之后,我们可以随意的进行子线程和UI线程的切换。同时,我们也可以自己来定义Rx之线程池的实现,合理分配应用的线程,本来就是应用开发的重中之重。本节以模拟两个线程池为例,来演示并讲解Schedulers。
首先我们自己构造一个Observable:
public static Observable<Integer> computeSum(final int n){
return Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
try{
int sum = 0;
for (int i = 0; i <= n; i ++){
sum += i;
}
System.out.println("computeSum on thread = " + Thread.currentThread());
subscriber.onNext(sum);
}catch (Throwable e){
subscriber.onError(e);
}finally {
subscriber.onCompleted();
}
}
});
}
在这个Observable里面,我们会打印出当前所在的线程。然后,我们构造出两个不同线程池的Schedulers,并且让这个Observable执行在不同的线程上:
Scheduler observeOnSchedule = Schedulers.from(Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "observeOnThread");
}
}));
Scheduler subscribeOnSchedule = Schedulers.from(Executors.newFixedThreadPool(3, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "mapSchedule");
}
}));
computeSum(1000).subscribeOn(subscribeOnSchedule).observeOn(observeOnSchedule).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
System.out.println("observeOn=======================" + Thread.currentThread());
}
});
运行结果如下:
computeSum on thread = Thread[subscribeOnThread,5,main]
observeOn=======================Thread[observeOnThread,5,main]
由此可见这个Observable执行在不同的线程池上。subscribeOn定义的为Observable中call执行所在的线程,而observeOn则定义的为subscribe执行所在的线程,为什么会如此神奇呢?我们来看看它是如何实现的。接下来一步步揭开来
subscribeOn运行流程
public final Observable<T> subscribeOn(Scheduler scheduler) {
if (this instanceof ScalarSynchronousObservable) {
return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler);
}
return nest().lift(new OperatorSubscribeOn<T>(scheduler));
}
方法很简单,首先判断当前observable是不是ScalarSynchronousObservable类型的,如果是则会直接执行scalarScheduleOn方法,如果不是,则会通过nest()方法创建一个ScalarSynchronousObservable并把当前的Observable包装进去,并且lift一个OperatorSubscribeOn进去。这一块说起来挺简单,内部源码看起来就有点晦涩了。但是溯根追源,我们来看下observable经过这一些列之后的变化,就会清晰很多了。
看图可以知道,这个过程中,最终生成了三个Observable,而当执行subscribe方法的时候,则一次执行的为最后生成的Observable的call方法也就是如下代码:
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
onSubscribe.call(st);
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}
});
}
其中Subscriber <? super T> st = hook.onLift(operator).call(o);
(暂且称之为sub1)返回的为OperatorSubscribeOn执行call方法执行的结果,这里稍后的再说。继续往下走,最终会发现,调用的为ScalarSynchronousObservable的onSubscribe的call方法,传递参数为sub1。这里的方法很简单:
protected ScalarSynchronousObservable(final T t) {
super(new OnSubscribe<T>() {
@Override
public void call(Subscriber<? super T> s) {
/*
* We don't check isUnsubscribed as it is a significant performance impact in the fast-path use cases.
* See PerfBaseline tests and https://github.com/ReactiveX/RxJava/issues/1383 for more information.
* The assumption here is that when asking for a single item we should emit it and not concern ourselves with
* being unsubscribed already. If the Subscriber unsubscribes at 0, they shouldn't have subscribed, or it will
* filter it out (such as take(0)). This prevents us from paying the price on every subscription.
*/
s.onNext(t);
s.onCompleted();
}
});
this.t = t;
}
只是简单的执行了sub1的onNext(t)方法和onComplete方法。请注意这里,t为我们最原始的observable也就是我们的compute的observable。
@Override
public Subscriber<? super Observable<T>> call(final Subscriber<? super T> subscriber) {
final Worker inner = scheduler.createWorker();
subscriber.add(inner);
return new Subscriber<Observable<T>>(subscriber) {
@Override
public void onCompleted() {
// ignore because this is a nested Observable and we expect only 1 Observable<T> emitted to onNext
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(final Observable<T> o) {
inner.schedule(new Action0() {
@Override
public void call() {
final Thread t = Thread.currentThread();
o.unsafeSubscribe(new Subscriber<T>(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);
}
});
}
}
});
}
});
}
});
}
};
}
这个是OperatorSubscribeOn的call方法,看上面的讲解我们可以明白,最终调用的sub1的onNext(t)方法就是这里的onNext方法,传递的Observable就是最初是的observable。而这里的inner创建是由ExecutorScheduler类创建的(具体看 Schedulers类就明白),所以inner也就是ExecutorSchedulerWorker的实例,最终调用的是ExecutorSchedulerWorker类的schedule方法,如下:
@Override
public Subscription schedule(Action0 action) {
if (isUnsubscribed()) {
return Subscriptions.unsubscribed();
}
ScheduledAction ea = new ScheduledAction(action, tasks);
tasks.add(ea);
queue.offer(ea);
if (wip.getAndIncrement() == 0) {
try {
// note that since we schedule the emission of potentially multiple tasks
// there is no clear way to cancel this schedule from individual tasks
// so even if executor is an ExecutorService, we can't associate the future
// returned by submit() with any particular ScheduledAction
executor.execute(this);
} catch (RejectedExecutionException t) {
// cleanup if rejected
tasks.remove(ea);
wip.decrementAndGet();
// report the error to the plugin
RxJavaPlugins.getInstance().getErrorHandler().handleError(t);
// throw it to the caller
throw t;
}
}
return ea;
}
此处代码就是把ScheduledAction放进queue里面,然后不停的从queue里面取出ScheduledAction并执行run方法,而run方法里面就是上一级里面onNext里面的call方法,具体可以去看代码,里面就是执行observable(最初的observable)的call方法等等。。如此,一系列observable的操作都是放在了我们最初创建的线程池里了。
observeOn运行流程
上面分析了如何让Observable的代码运行在其它线程里,接下来分析下,如何让Subscriber运行在其他线程里。这里比较简单,因为Subscriber的代码逻辑要比上面的简单。因为Observable是经过层层包装以及变幻,最终生成的Observable已经不是最初的Observable,而Subscriber虽然也有很多个,但是最终值得我们关注的却只有最后一个。接下来看具体代码逻辑,首先是observeOn方法:
public final Observable<T> observeOn(Scheduler scheduler) {
if (this instanceof ScalarSynchronousObservable) {
return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler);
}
return lift(new OperatorObserveOn<T>(scheduler));
}
这里比较简单,Observable并没有经过什么变换,而是直接lift一个OperatorObserveOn,产生的Observable为(本次不测试subscribeOn):
由此可见,最终执行的为OperatorObserveOn的onNext方法。。如下:
@Override
public void onNext(final T t) {
if (isUnsubscribed()) {
return;
}
if (!queue.offer(on.next(t))) {
onError(new MissingBackpressureException());
return;
}
schedule();
}
把Observable处理过的对象放到queue里面,这里的queue可能会存多个t(当observable执行的很快而且Subscriber并没有unsubscribe的时候,如果Subscriber的onNext方法执行较慢的时候)。而schedule方法就是在当前指定的Scheduler所在在线程上面执行pollQueue:
final Action0 action = new Action0() {
@Override
public void call() {
pollQueue();
}
};
protected void schedule() {
if (counter.getAndIncrement() == 0) {
recursiveScheduler.schedule(action);
}
}
schedule里面只是判断下当前是否在线程里面执行onNext方法。来看pollQueue:
void pollQueue() {
int emitted = 0;
final AtomicLong localRequested = this.requested;
final AtomicLong localCounter = this.counter;
do {
localCounter.set(1);
long produced = 0;
long r = localRequested.get();
for (;;) {
if (child.isUnsubscribed())
return;
Throwable error;
if (finished) {
if ((error = this.error) != null) {
// errors shortcut the queue so
// release the elements in the queue for gc
queue.clear();
child.onError(error);
return;
} else
if (queue.isEmpty()) {
child.onCompleted();
return;
}
}
if (r > 0) {
Object o = queue.poll();
if (o != null) {
child.onNext(on.getValue(o));
r--;
emitted++;
produced++;
} else {
break;
}
} else {
break;
}
}
if (produced > 0 && localRequested.get() != Long.MAX_VALUE) {
localRequested.addAndGet(-produced);
}
} while (localCounter.decrementAndGet() > 0);
if (emitted > 0) {
request(emitted);
}
}
代码虽然很多,其实多数只是执行一些逻辑判断,其主要的含义就是,设置counter为1,然后不停的从queue里面取数据,然后调用child的onNext方法(child为最原始我们定义的Subcriber),直到把queue里面的数据取完之后,方法结束。
综上所述,可以看出,subscribeOn所执行的操作是用Observable来包装原来的Observable,而observeOn所执行的操作是用一个ObserveOnSubscriber来包装我们定义的Subscriber。RxJava原来难懂的地方也在这里,对象层层包装,然后像个钩子一样层层回调回来,就形成了流水线一样的过程。
杏树林研发 徐英建