【Rxjava2源码系列】线程调度(二)

一、前言

上一篇文章:【Rxjava2源码系列】基本订阅、消耗事件流程(一)
已经弄清楚了Rxjava的整体流程,本文就来看看Rxjava强大的线程转换能力。

相信大家最常用到Rxjava的地方就是利用Retrofit做网络请求了吧?不仅如此,只要有耗时操作,都可以考虑利用Rxjava来实现,就是这么任性。本文要研究的包括
1、线程调度如何实现?

2、subscribeOn、observeOn有什么区别

二、subscribeOn、observeOn

一般,我们使用subscribeOn和observeOn来切换线程,我们首先来看看subscribeOn,打开它的源码发现和我们以前分析的map、create之类的方法一样,最终走到了subscribeActual,具体流程上一篇文章已经分析过了,这里我仅贴上代码,方便大家查看

    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> subscribeOn(Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
    }



====================================================================================
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
    final Scheduler scheduler;

    public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
        super(source);
        this.scheduler = scheduler;
    }

    @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() {
                //线程转换后进行subscribe操作
                source.subscribe(parent);
            }
        }));
    }
    }

可以看见,ObservableSubscribeOn里同样有自己的observer:SubscribeOnObserver,这里我们不管,直接看最重要的一句:scheduler.scheduleDirect,调用了scheduler的方法,传入了一个runnable,跟进去看看

    public Disposable scheduleDirect(Runnable run) {
        return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
    }



    public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
        //调用createWorker返回一个worker
        final Worker w = createWorker();
        //RxJavaPlugins的hook操作,暂时无视
        final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

        //调用work的schedule方法传入一个runnable对象
        w.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    //手动调用了run方法
                    decoratedRun.run();
                } finally {
                    w.dispose();
                }
            }
        }, delay, unit);

        return w;
    }

    //Scheduler类的抽象方法,在子类中实现
   public abstract Worker createWorker();

这里调用createWorker返回了一个worker,createWorker是一个抽象方法由子类实现,想必就是IO、Main等scheduler去实现的。接下来就调用了worker的schedule方法传入一个runnable,就是这里做的异步操作了,由子类控制是在哪个线程操作,值得注意的是刚刚传入的runnable并没有start,而是直接调用的run方法。

由此可知后面执行的observable的subscribe方法就会调用在此线程中,完成了线程的切换。

具体等会再详细讨论如何进行的异步,我们先来看看observeOn方法,同样在一系列调用之后到了subscribeActual方法里。

    @Override
    protected void subscribeActual(Observer<? super T> observer) {
        if (scheduler instanceof TrampolineScheduler) {
            //TrampolineScheduler直接在当前线程中执行,无需转换线程
            source.subscribe(observer);
        } else {
            //直接调用createWorker返回worker
            Scheduler.Worker w = scheduler.createWorker();
            //将操作转到ObserveOnObserver中
            source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
        }
    }

接着看ObserveOnObserver实现

    static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
    implements Observer<T>, Runnable {
    //省略成员、构造函数、onSubscribe等

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

            if (sourceMode != QueueDisposable.ASYNC) {
                queue.offer(t);
            }
            schedule();
        }

        //省略error等方法

        void schedule() {
            if (getAndIncrement() == 0) {
                worker.schedule(this);
            }
        }

        void drainNormal() {
            int missed = 1;

            final SimpleQueue<T> q = queue;
            final Observer<? super T> a = actual;

            for (;;) {
                if (checkTerminated(done, q.isEmpty(), a)) {
                    return;
                }

                for (;;) {
                    boolean d = done;
                    T v;

                    try {
                        v = q.poll();
                    } catch (Throwable ex) {
                        Exceptions.throwIfFatal(ex);
                        s.dispose();
                        q.clear();
                        a.onError(ex);
                        return;
                    }
                    boolean empty = v == null;

                    if (checkTerminated(d, empty, a)) {
                        return;
                    }

                    if (empty) {
                        break;
                    }

                    a.onNext(v);
                }

                missed = addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }

        void drainFused() {
            int missed = 1;

            for (;;) {
                if (cancelled) {
                    return;
                }

                boolean d = done;
                Throwable ex = error;

                if (!delayError && d && ex != null) {
                    actual.onError(error);
                    worker.dispose();
                    return;
                }

                actual.onNext(null);

                if (d) {
                    ex = error;
                    if (ex != null) {
                        actual.onError(ex);
                    } else {
                        actual.onComplete();
                    }
                    worker.dispose();
                    return;
                }

                missed = addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }

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

可以看见ObserveOnObserver实现了runnable,当执行到onNext时,就会调用worker的schedule方法,这里和subscribeOn一样进行了异步调用。由于传入的是This,所以会执行run方法,经过一系列判断依然会调用onNext方法。

此时已经进行过线程转换,所以下游的observer的onNext也会执行在此线程了。

三、scheduler

搞清楚了线程如何切换,接下来继续看看异步操作是如何产生的,刚刚我说是worker的schedule方法产生的异步,而worker又是子类createWorker方法生成的,所以我们直接去看子类的该方法。
一般我们线程转换会调用如下代码:

                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())

先来看看Schedulers.io(),他返回的是一个IoScheduler类,看看他的createWorker

    @Override
    public Worker createWorker() {
        return new EventLoopWorker(pool.get());
    }

返回了一个EventLoopWorker,参数是CachedWorkerPool,看名字就知道是任务缓存池了,由于不是我们的重点就不过多讲解了,我们来看看这个worker

    static final class EventLoopWorker extends Scheduler.Worker {
        private final CompositeDisposable tasks;
        private final CachedWorkerPool pool;
        private final ThreadWorker threadWorker;

        final AtomicBoolean once = new AtomicBoolean();

        EventLoopWorker(CachedWorkerPool pool) {
            this.pool = pool;
            this.tasks = new CompositeDisposable();
            this.threadWorker = pool.get();
        }
        //.....
        @Override
        public Disposable schedule(Runnable action, long delayTime, TimeUnit unit) {
            if (tasks.isDisposed()) {
                // don't schedule, we are unsubscribed
                return EmptyDisposable.INSTANCE;
            }

            return threadWorker.scheduleActual(action, delayTime, unit, tasks);
        }
    }

我们可以看到schedule方法其实是调用了threadWorker的scheduleActual方法。而threadWorker是一个ThreadWorker 实例,ThreadWorker 继承于NewThreadWorker,scheduleActual方法就实现在里面了

    public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, TimeUnit unit, DisposableContainer parent) {
        //RxJavaPlugins钩子,暂时无视...
        Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
        //封装了传入的runnable,可以当做Future进行任务管理
        ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
        //存入container容器中
        if (parent != null) {
            if (!parent.add(sr)) {
                return sr;
            }
        }
        //可以管理任务
        Future<?> f;
        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) {
            parent.remove(sr);
            RxJavaPlugins.onError(ex);
        }

        return sr;
    }

好了,到这里已经很清晰了,是利用线程池执行了任务,实现了线程转换。
接下来我们看看AndroidSchedulers.mainThread(),他返回的是HandlerScheduler对象,看名字就很熟悉啦~依旧看看他的createWorker方法

    @Override
    public Worker createWorker() {
        return new HandlerWorker(handler);
    }

继续跟进HandlerWorker

    private static final class HandlerWorker extends Worker {
        private final Handler handler;

        private volatile boolean disposed;

        HandlerWorker(Handler handler) {
            this.handler = handler;
        }

        @Override
        public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
            if (run == null) throw new NullPointerException("run == null");
            if (unit == null) throw new NullPointerException("unit == null");

            if (disposed) {
                return Disposables.disposed();
            }

            run = RxJavaPlugins.onSchedule(run);

            ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);

            Message message = Message.obtain(handler, scheduled);
            message.obj = this; // Used as token for batch disposal of this worker's runnables.

            handler.sendMessageDelayed(message, Math.max(0L, unit.toMillis(delay)));

            // Re-check disposed state for removing in case we were racing a call to dispose().
            if (disposed) {
                handler.removeCallbacks(scheduled);
                return Disposables.disposed();
            }

            return scheduled;
        }
//......
    }

也很简单,就是利用handler转换线程啦!而这个handler是在构造时传入的,也就是这里:

static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));

OK,获取的是main线程的looper,也就是可以转换到主线程了。

四、subscribeOn、observeOn区别

这个问题可能是很多Rxjava使用者的共同话题,笔者也很长一段时间没有弄清楚。仔细的读者可能已经发现我之前特意加粗的两行字,这里再放出来对比一下:
subscribeOn:由此可知后面执行的observable的subscribe方法就会调用在此线程中,完成了线程的切换。
observeOn:此时已经进行过线程转换,所以下游的observer的onNext也会执行在此线程了。

阅读过我的上一篇文章的读者也许已经明白的他们之间的差别,没错,一个是subscribe方法异步,而另一个是onNext(系列)方法异步,为了能更好理解,我就再整个梳理一遍。下面列出比较简单的一个线程转换示例:

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("1");
                e.onComplete();
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .map(new Function<String, String>() {
                    @Override
                    public String apply(String s) throws Exception {
                        return "_"+s;
                    }
                })
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.d(TAG, "onSubscribe() called with: d = [" + d + "]");
                    }

                    @Override
                    public void onNext(String value) {
                        Log.d(TAG, "onNext() called with: value = [" + value + "]");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d(TAG, "onError() called with: e = [" + e + "]");
                    }

                    @Override
                    public void onComplete() {
                        Log.d(TAG, "onComplete() called");
                    }
                });

转换为图片之后:
这里写图片描述
好了,梳理完了(斜眼笑),没有逗你,精华就是这张图了,PS:图中横向箭头指的是持有,执行顺序大多是纵向箭头
看图说话:
1、无论subscribeOn调用多少次,真正起作用的也就只有最靠近我们创建Observable的那个有效(也就是网上大多数的说法:第一次调用有效)
2、observeOn只会影响下游的observable,可以多次生效

OK,线程调度就讲解完了,期待下一篇吧^ ^。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值