Rxjava基本原理解析(四)

    接着上一篇的分享模式,今天我们介绍和分析线程切换操作符subscribeOn以及其源码设计。

    Rxjava的一个最大优点之一就是灵活的线程切换,切换过程不影响整体链式逻辑流程,既方便又清新。为了对比,还是再次将一个操作符的结构图放上:

结构图

subscribeOn操作符用于切换事件源的线程,一般用在第一个observable的后面:

Observable.create((ObservableOnSubscribe<String>) e -> e.onNext("hello"))
       .subscribeOn(Schedulers.newThread())
       .subscribe(s -> System.out.println("onNext"));

    与上一篇create操作符的使用代码相比少了很多,原因是使用链式写法和lambda表达式。create操作符的事件源还是一个ObservableOnSubscribe对象,但是订阅的不再是observer,而是一个Consumer,这个后面文章会讲解。

    subscribeOn操作符需要传一个scheduler用于指定线程,然后创建一个被观察者:ObservableSubscribeOn和一个观察者SubscribeOnObserver。 ObservableSubscribeOn的source为上一个observable,核心代码在subscribeActual()方法中,源码如下:

@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);
        }
    }));
}

     subscribeOn操作符是改变事件源的线程,即设置上一个observable.subscribe的线程。subscribeActual方法中不是直接调用source.subscribe(parent)而是通过传入的scheduler调用。由于传入的scheduler指定了新的线程,那么scheduler内部会切换到指定线程调用source.subscribe(parent);实现切换线程。

observable

    下面来看看scheduler内部是如何实现线程切换的。本篇以新线程Schedulers.newThread()为例进行分析,其他线程模式以及对比分析后面会单独写一篇。Scheduler通过入口方法scheduleDirect传入一个runable接口,通过runable的run方法调用source.subscribe(parent);,scheduleDirect内部实际是调用如下的重载方法:

public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
        final Worker w = createWorker();
        final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
        w.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    decoratedRun.run();
                } finally {
                    w.dispose();
                }
            }
        }, delay, unit);
        return w;
}

    该方法调用了createWorker()获得一个Worker,然后通过调用worker的schedule方法来调用传入的runable接口方法。createWorker是个抽象方法,需要子类重新。Schedulers.newThread()得到的实际是个Scheduler子类对象NewThreadScheduler。该类重新了createWorker并得到一个Worker的子类NewThreadWorker。那么真正的线程切换就是靠Worker来控制的。NewThreadWorker的schedule方法实际调用的是scheduleActual方法,NewThreadWorker的scheduleActual源码如下:

public ScheduledRunnable scheduleActual(final Runnable run, ...) {
        Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
        ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
       //...
        try {
            if (delayTime <= 0) {
                f = executor.submit((Callable<Object>)sr);
            } else {
                f = executor.schedule((Callable<Object>)sr, delayTime, unit);
            }
            sr.setFuture(f);
        } 
        catch (RejectedExecutionException ex) {
            //...
        }
        return sr;
}

方法内会使用线程池executor.submit((Callable<Object>)sr)去执行传入的runable接口方法,调用订阅方法,实现线程切换。整体流程线程变换如下图所示:

整体流程

注意以下两点:

    1.根据ObservableSubscribeOn 的subscribeActual源码可知,s.onSubscribe(parent)在线程切换前执行,那么onSubscribe不受subscribeOn线程切换影响,在原线程执行;

    2.在使用subscribeOn操作符切换到新线程后,上游的所有subscribe订阅方法都会在新线程执行,一直穿透到事件源。如果整链式操作中,上游有新的subscribeOn操作符,那么线程又会改变,因此多个subscribeOn后,只有第一个会对事件源线程有效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值