Rxjava(二)——线程切换怎么实现的?

接上文Rxjava(一)——链式调用怎么实现的?
在分析线程切换原理前要明白几个概念;

线程调用的关键操作符subscribeOn、observeOn

observeOn作用:影响后续操作符所在的线程,直到下个observeOn设置为其他线程;
subscribeOn作用:初始化整个链条所在的线程,多次设置只有第一次生效;

线程调度器 Schedulers

Rxjava里面将常用线程归纳为4种,即有4 种调度器:

  • 主线程 AndroidSchedulers.mainThread();
  • io线程 Schedulers.io()
  • 计算线程 Schedulers.computation()
  • 新建线程 Schedulers.newThread()

同样以一个实例来进行分析:

    Observable.just("a")
               .observeOn(Schedulers.computation())
                .map(new Func1() {  //操作1
                    @Override
                    public String call(String s) {
                        System.out.print(Thread.currentThread().getName() + ":first--" + s +"\n");
                        return s + s;
                    }
                })
                 .observeOn(Schedulers.io())
                .map(new Func1() { //操作2
                    @Override
                    public String call(String s) {
                        System.out.print(Thread.currentThread().getName() + ":second--" + s+"\n");
                        return s + s;
                    }
                })
                .subscribeOn(Schedulers.newThread())
                .subscribe(new Subscriber() {//操作3
                    @Override
                    public void onCompleted() {
                        System.out.print(Thread.currentThread().getName()+"\n");
                        System.out.print("completed"+"\n");

                    }

                    @Override
                    public void onError(Throwable e) {
                        System.out.print("error");
                    }

                    @Override
                    public void onNext(String s) {
                        System.out.println(s);
                    }
                });

上述实例中,分别使用了computation线程、io线程和新线程,执行代码如下:


Rxjava(二)——线程切换怎么实现的?_第1张图片
image.png

由于subscribeOn是在整个调用链之前,其作用于整个链条,而observeOn只作用此它操作符之后,因此上图结束RxComputationThreadPool-1 在计算线程中,而之后的全部都处理io()线程RxCachedThreadScheduler-1中。

正式开始撸代码

带着几个问题来跟读代码:

  • 1 Observable.just("a")生成的Observable对象,如何调用到计算线程中,线程切换通过什么实现的?
  • 2 为什么subscribeOn()是对整个调用链条起作用?

问题1:Observable.just("a")生成的Observable对象,如何调用到计算线程中,线程切换通过什么实现的?

Observable.just("a").observeOn(Schedulers.computation())

由于just发送的单个对象,因此Observable使用的创建对象为ScalarSynchronousObservable;在其初始化对象时,将"a"作为构造参数传入,并保存。
observeOn操作符会首先对Observable的类型进行检测,若为ScalarSynchronousObservable类型,则通过ScalarSynchronousObservable@scalarScheduleOn来实现在某个线程中调度的过程;
跟进ScalarSynchronousObservable类,

    public Observable scalarScheduleOn(Scheduler scheduler) {
        if (scheduler instanceof EventLoopsScheduler) {
            EventLoopsScheduler es = (EventLoopsScheduler) scheduler;
            return create(new DirectScheduledEmission(es, t));
        }
        return create(new NormalScheduledEmission(scheduler, t));
    }

很显然,使用DirectScheduledEmission,通过call,完成计算线程池的直接调度。

  static final class DirectScheduledEmission implements OnSubscribe {
        private final EventLoopsScheduler es;
        private final T value;
        DirectScheduledEmission(EventLoopsScheduler es, T value) {
            this.es = es;
            this.value = value;
        }
        @Override
        public void call(final Subscriber child) {
            child.add(es.scheduleDirect(new ScalarSynchronousAction(child, value)));
        }
    }
    //EventLoopsScheduler.class
    public Subscription scheduleDirect(Action0 action) {
       PoolWorker pw = pool.get().getEventLoop();
       return pw.scheduleActual(action, -1, TimeUnit.NANOSECONDS);
    }
    public ScheduledAction scheduleActual(final Action0 action, long delayTime, TimeUnit unit) {
        Action0 decoratedAction = schedulersHook.onSchedule(action);
        ScheduledAction run = new ScheduledAction(decoratedAction);
        Future f;
        if (delayTime <= 0) {
            f = executor.submit(run);//执行动作
        } else {
            f = executor.schedule(run, delayTime, unit);
        }
        run.add(f);

        return run;
    }

到此时,executor.submit(run);执行,切换到对应线程上完成Action的调用;而Action里面做的什么事, 找到实现方法,发现其call()方法就是将数据传递到下一层去而已:

    /** Action that emits a single value when called. */
    static final class ScalarSynchronousAction implements Action0 {
        private final Subscriber subscriber;
        private final T value;

        private ScalarSynchronousAction(Subscriber subscriber,
                T value) {
            this.subscriber = subscriber;
            this.value = value;
        }

        @Override
        public void call() {
            try {
                subscriber.onNext(value);
            } catch (Throwable t) {
                subscriber.onError(t);
                return;
            }
            subscriber.onCompleted();
        }
    }

问题一到此,就分析得差不多了。

问题2: 为什么subscribeOn()是对整个调用链条起作用?

 return nest().lift(new OperatorSubscribeOn(scheduler));

能对整个调用链起作用的关键点是nest();为什么这么说,看其实现;

  public final Observable> nest() {
        return just(this);
    }

在此,可以看到其实还是使用的just,但是,关键是发送的观察者是this;发送this,就意味着subscribeOn所在的Observable对象发送了出去。this所代表的对象将会作为一个嵌套链表嵌入到subscribeOn所产生的新的Observable调用链中;
那么this如何嵌入到新的Observable中的呢?
查看OperatorSubscribeOn类源码,关键代码o.unsafeSubscribe

  @Override
    public Subscriber> call(final Subscriber subscriber) {
        final Worker inner = scheduler.createWorker();
        subscriber.add(inner);
        return new Subscriber>(subscriber) {

            @Override
            public void onCompleted() {
                // ignore because this is a nested Observable and we expect only 1 Observable emitted to onNext
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }

            @Override
            public void onNext(final Observable o) {
                inner.schedule(new Action0() {

                    @Override
                    public void call() {
                        final Thread t = Thread.currentThread();
                        o.unsafeSubscribe(new Subscriber(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);
                                                }
                                            });
                                        }
                                    }

                                });
                            }

                        });
                    }
                });
            }

        };
    }
}

此处的o对象就是nest发送的this,通过unsafeSubscribe函数,重新形成调用链;
此处在执行的同时还存在线程切换,即inner.schedule。

你可能感兴趣的:(Rxjava(二)——线程切换怎么实现的?)