RxJava之Schedulers详解

来源:互联网 发布:文艺知乎 编辑:程序博客网 时间:2024/05/22 06:45

本来是想说说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。

@Overridepublic 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 0
原创粉丝点击