RxJava之Schedulers详解

本来是想说说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原来难懂的地方也在这里,对象层层包装,然后像个钩子一样层层回调回来,就形成了流水线一样的过程。

                                                        杏树林研发 徐英建
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值