RxJava之Scheduler (三) ——线程调度

325 阅读5分钟

默认情况下,不做任何线程处理,Observable和Observer处于同一线程中。如果想要切换线程,则可以使用subscribeOn()和observeOn()。

1.subscribeOn

subscribeOn通过接受一个Scheduler参数,来指定对数据的处理运行在特定的线程调度器Scheduler上。 若多次执行subscribeOn,则只有一次起作用

单击subscribeOn()的源码可以看到,每次调用subscribeOn()都会创建一个ObservableSubscribeOn对象。

    /**
     * Asynchronously subscribes Observers to this ObservableSource on the specified {@link Scheduler}.
     *
     * @param scheduler
     *            the {@link Scheduler} to perform subscription actions on
     * @return the source ObservableSource modified so that its subscriptions happen on the
     *         specified {@link Scheduler}
     * @see #observeOn
     */
    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> subscribeOn(Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
    }

ObservableSubscribeOn真正发生订阅的方法是subscribeActual(Observer<? super T> observer)。

    @Override
    public void subscribeActual(final Observer<? super T> s) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);

        s.onSubscribe(parent);

        parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
            @Override
            public void run() {
                source.subscribe(parent);
            }
        }));
    }

其是,SubscribeOnObserver是下游Observer的OnSubscribe(Disposable disposable)方法

    s.onSubscribe(parent);

然后,将子线程的操作加入Disposable管理中,加入Disposable后可以方便上下游的统一管理。在这里,已经调用了对应Scheduler的scheduleDirect()方法。scheduleDirect()传入的是一个Runnable。

        parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
            @Override
            public void run() {
                source.subscribe(parent);
            }
        }));

此时,已经再对应的Scheduler线程中运行了:

source.subscribe(parent);

在RxJava的链式操作中,数据的处理是自下而上的,这点与数据发射正好相反。如果多次调用subscribeOn,则最上面的线程切换最晚执行,所以就变成了只有第一次切换线程有效

2.observeOn

observeOn同样接受一个Scheduler参数,用来指定下游操作运行在特定的线程调度器Scheduler上。

若多次执行observeOn,则每次都起作用,线程会一直切换。

单击observeOn的源码可以看到,每次调用observeOn()都会创建一个ObservableObserveOn对象。

    /**
     * Modifies an ObservableSource to perform its emissions and notifications on a specified {@link Scheduler},
     * asynchronously with an unbounded buffer with {@link Flowable#bufferSize()} "island size".
     *
     * <p>Note that onError notifications will cut ahead of onNext notifications on the emission thread if Scheduler is truly
     * asynchronous. If strict event ordering is required, consider using the {@link #observeOn(Scheduler, boolean)} overload.
     *
     * @param scheduler
     *            the {@link Scheduler} to notify {@link Observer}s on
     * @return the source ObservableSource modified so that its {@link Observer}s are notified on the specified
     *         {@link Scheduler}
     */
    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> observeOn(Scheduler scheduler) {
        return observeOn(scheduler, false, bufferSize());
    }
    
    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        ObjectHelper.verifyPositive(bufferSize, "bufferSize");
        return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
    }

ObservableObserveOn真正发生订阅的方法是subscribeActual(Observer<? super T> observer)。

    @Override
    protected void subscribeActual(Observer<? super T> observer) {
    
        //如果scheduler是TrampolineScheduler,则上游事件和下游事件会立即产生订阅。
        if (scheduler instanceof TrampolineScheduler) {
            source.subscribe(observer);
        } else {
            //否则scheduler会创建自己的Worker,然后上游事件和下游事件产生订阅,生成一个ObserveOnObserver对象,封装了下游真正的Observer。
            Scheduler.Worker w = scheduler.createWorker();

            source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
        }
    }

如果scheduler是TrampolineScheduler,则上游事件和下游事件会立即产生订阅。

如果不是TrampolineScheduler,则scheduler会创建自己的Worker,然后上游事件和下游事件产生订阅,生成一个ObserveOnObserver对象,封装了下游真正的Observer。

ObserveOnObserverObservableObserveOn的内部类,实现了Observer、Runnable接口。与SubscribeOnObserver不同的是,SubscribeOnObserver实现了Observer、Disposable接口

在ObserveOnObserver的onNext()中,schedule()执行了具体调度的方法。

        @Override
        public void onNext(T t) {
            if (done) {
                return;
            }

            if (sourceMode != QueueDisposable.ASYNC) {
                queue.offer(t);
            }
            schedule();
        }
        
        void schedule() {
            if (getAndIncrement() == 0) {
               // 该成员变量worker: final Scheduler.Worker worker;
               // this指的是当前的ObserveOnObserver对象,this实现了 Runnable接口
                worker.schedule(this);
            }
        }

然后,再来看看Runnable接口的实现方法run(),这个方法是在Worker对应的线程里执行的。drainNormal()会取出ObserveOnObserver的queue里的数据进行发送。

        @Override
        public void run() {
            if (outputFused) {
                drainFused();
            } else {
                drainNormal();
            }
        }

下游多次调用observeOn(),则线程会一直切换。每次切换线程,都会把对应的Observe对象各个方法的处理执行在指定的线程中

注意:这是与subscribeOn()方法的不同之处,多次subscribeOn(),只有一次起作用。

简单示例:

    public void multipleUsingSubscribeOnAndObserveOnTest() {
        Observable.just("HELLO WORLD")
                .subscribeOn(Schedulers.single())
                .map(new Function<String, String>() {
                    @Override
                    public String apply(@NonNull String s) throws Exception {
                        s = s.toLowerCase();
                        print("map1:");
                        System.out.println(s);
                        return s;
                    }
                })
                .observeOn(Schedulers.io())
                .map(new Function<String, String>() {
                    @Override
                    public String apply(@NonNull String s) throws Exception {
                        s = s + " tony.";
                        print("map2");
                        System.out.println(s);
                        return s;
                    }
                })
                .subscribeOn(Schedulers.computation())
                .map(new Function<String, String>() {
                    @Override
                    public String apply(@NonNull String s) throws Exception {
                        s = s + " it is a test.";
                        print("map3");
                        System.out.println(s);
                        return s;
                    }
                })
                .observeOn(Schedulers.newThread())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        print("subscribe");
                        System.out.println(s);
                    }
                });
    }

    public void print(String label) {
        System.out.println(label);
        System.out.println(Thread.currentThread().getName());
    }

输出结果:

2020-06-23 14:51:31.699 2627-2646/? I/System.out: map1:
2020-06-23 14:51:31.699 2627-2646/? I/System.out: RxSingleScheduler-1
2020-06-23 14:51:31.699 2627-2646/? I/System.out: hello world
2020-06-23 14:51:31.701 2627-2647/? I/System.out: map2
2020-06-23 14:51:31.701 2627-2647/? I/System.out: RxCachedThreadScheduler-1
2020-06-23 14:51:31.701 2627-2647/? I/System.out: hello world tony.
2020-06-23 14:51:31.702 2627-2647/? I/System.out: map3
2020-06-23 14:51:31.702 2627-2647/? I/System.out: RxCachedThreadScheduler-1
2020-06-23 14:51:31.702 2627-2647/? I/System.out: hello world tony. it is a test.
2020-06-23 14:51:31.703 2627-2648/? I/System.out: subscribe
2020-06-23 14:51:31.703 2627-2648/? I/System.out: RxNewThreadScheduler-1
2020-06-23 14:51:31.703 2627-2648/? I/System.out: hello world tony. it is a test.

说明: 在多次使用subscribeOn和observeOn时,如同上述例子, 具体的调用线程说明:

  • subscribeOn(): Schedulers.single()
  • observeOn():Schedulers.io()
  • subscribeOn():Schedulers.io()

注意:此处调用的线程 不是 Schedulers.single(),因为已经调用过一次subscribeOn(),因而再次调用该方法时会使用其上一次的线程,即 observeOn()所调用的线程 ,但不是上一次subscribeOn()的线程!!!

  • observeOn():Schedulers.newThread()