RxJava2.X源码分析(三):探索RxJava2之观察者线程切换原理

一 前言

基于RxJava2.1.1
我们在前面的 Rxjava 2 的源码解析初步分析了RxJava从创建到执行的流程,分析了RxJava的随意终止Reactive流的能力的来源;也明白了RxJava的onComplete();与onError(t);只有一个会被执行的秘密。RxJava2.X 源码分析(二)中探索了RxJava2调用subscribeOn切换被观察者线程的原理。
本次我们将继续探索RxJava2.x切换观察者的原理,分析observeOn与subscribeOn的不同之处。继续实现我们在第一篇中定下的小目标

二 从Demo到原理

这里就不粘贴代码了,大家可以去RxJava2.X 源码分析(二 )这里看demo,我们直接来看observeOn这个方法:

Class Obsevable{
    
    
......
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> observeOn(Scheduler scheduler) {
    
    
    //false为默认无延迟发送错误,bufferSize为缓冲区大小
    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));
    }
......
}

看到这里其实大家也应该猜到了,observeOn和subscribeOn执行流程基本都是一样的,都是传入原被观察者已经线程调度器,通过最后的subribe()方法,调用了原被观察者的包装类(ObservableObserveOn)中的subscribeActual()方法,在此方法中对传入的原观察者进行一次包装,其次根据传入的线程调度器,实现线程的切换,同时在Runeable的run方法中调用原被观察者的subribe(),执行原被观察者的subscribeActual()方法,同时执行原观察者的包装类里的方法(里面封装了原观察者的方法)。我们接下来看看是否是这样的原理:

先来看看ObservableObserveOn:
在这里插入图片描述
很显然,ObservableObserveOn其实就是一个Obserable,即是被观察者的包装类,接着我们在来看看里面的subscribeActual()方法:

      @Override
    protected void subscribeActual(Observersuper T> observer) {
    
    
         //1、在当前线程调度,但不是立即执行,放入队列中
          if (scheduler instanceof TrampolineScheduler) {
    
    
              source.subscribe(observer);
          } else {
    
    
           //2、本次走的是这里
              Scheduler.Worker w = scheduler.createWorker();
            //3
              source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
          }
      }

Ok,果然,熟悉的模式,对我们上游的Observable,下游的Observerwrapper一次。
1、ObservableObserveOn继承了AbstractObservableWithUpstream
2、source保存上游的Observable
3、scheduler为本次的调度器
4、在下游调用subscribe订阅时触发->subscribeActual->Wrapper了下游的Observer观察者
3处:source为上游Observable(原Observable),下游Observer(原Observer)被wrapper到ObserveOnObserver,发生订阅数件,上游Observable(原Observable)开始执行subscribeActual,调用ObserveOnObserver的onSubscribe以及onNext、onError、onComplete等

OK,我们接着看Observer被包装进 ObserveOnObserver的样子,代码有点多,我们分段讲解:
先来看看 onSubscribe方法:


Class ObservableObserveOn{
    
    

static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
    implements Observer<T>, Runnable {
    
    

        private static final long serialVersionUID = 6576896619930983584L;
        //下游的Observer
        final Observersuper T> actual;
        //调度工作者
        final Scheduler.Worker worker;
        //是否延迟错误,默认false
        final boolean delayError;
        //队列大小
        final int bufferSize;
        //存储上游Observable下发的数据队列
        SimpleQueue<T> queue;
        //存储下游Observer的Disposable
        Disposable s;
        //存储错误信息
        Throwable error;
        //校验是否完毕
        volatile boolean done;
        //是否被取消
        volatile boolean cancelled;
        //存储执行模式,同步或者异步 同步
        int sourceMode;

        boolean outputFused;

        ObserveOnObserver(Observersuper T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {
    
    
            this.actual = actual;
            this.worker = worker;
            this.delayError = delayError;
            this.bufferSize = bufferSize;
        }

        @Override
      public void onSubscribe(Disposable s) {
    
    

            if (DisposableHelper.validate(this.s, s)) {
    
    
                this.s = s;
                if (s instanceof QueueDisposable) {
    
    
                    @SuppressWarnings("unchecked")
                    QueueDisposable<T> qd = (QueueDisposable<T>) s;

                    int m = qd.requestFusion(QueueDisposable.ANY | QueueDisposable.BOUNDARY);

                  //1、判断执行模式并调用onSubscribe传递给下游Observer
                    if (m == QueueDisposable.SYNC) {
    
    
                        sourceMode = m;
                        queue = qd;
                        //true 后面的onXX方法都不会被调用
                        done = true;
                        actual.onSubscribe(this);
                        //2、同步模式下,直接调用schedule
                        schedule();
                        return;
                    }
                    if (m == QueueDisposable.ASYNC) {
    
    
                        sourceMode = m;
                        queue = qd;
                        actual.onSubscribe(this);
                        //2、异步模式下,等待schedule
                        return;
                    }
                }

                queue = new SpscLinkedArrayQueue<T>(bufferSize);
                //判断执行模式并调用onSubscribe传递给下游Observer
                actual.onSubscribe(this);
            }
        }
        ........
        }

OK,执行玩这里之后,就到我们的onNext方法了:

@Override
public void onNext(T t) {
    
    
   //3、数据源是同步模式或者执行过error / complete 会是true
  if (done) {
    
    
      return;
  }
  //如果数据源不是异步类型,
  if (sourceMode != QueueDisposable.ASYNC) {
    
    
      //4、上游Observable下发的数据压入queue
      queue.offer(t);
  }
  //5、开始调度
  schedule();
}

其次只能触发一次的onError,基本差不多

@Override
  public void onError(Throwable t) {
    
    
      if (done) {
    
    
          //6、已完成再执行会抛一场
          RxJavaPlugins.onError(t);
          return;
      }
      //7、记录错误信息
      error = t;
      //8、标识已完成
      done = true;
      //9、开始调度
      schedule();
  }

同样是只能触发一次的onComplete,同样的套路,就不说了

@Override
  public void onComplete() {
    
    
      if (done) {
    
    
          return;
      }
      done = true;
      schedule();
  }

我们重点来看一下schedule()这个方法:


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

这里调用的是worker(也就是我们在ObserverOn方法里指定的线程)中的schedule()方法,其中的参数是一个Runnable类型,传入的是this,说明观察者的包装类(ObserveOnObserver)是实现了Runnable接口的:

static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
    implements Observer<T>, Runnable 

接下看,继续调用 schedule( Runnable action, long delayTime, TimeUnit unit) 方法,但是这个方法是个抽象方法,这里我们就假设这里这个 worker 是 IO 线程,所以我直接贴 IoScheduler 的代码了:

public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
    
    
     if (tasks.isDisposed()) {
    
    
         // don't schedule, we are unsubscribed
         return EmptyDisposable.INSTANCE;
     }
     return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}

然后再贴一下 scheduleActual 的方法:

public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
    
    
    Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
    //就是个 Runnable
    ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
        
    if (parent != null) {
    
    
        if (!parent.add(sr)) {
    
    
            return sr;
        }
    }

    Future<?> f;
    try {
    
    
        //判断延迟时间,然后使用线程池运行 Runnable
        if (delayTime <= 0) {
    
    
            f = executor.submit((Callable<Object>)sr);
        } else {
    
    
            f = executor.schedule((Callable<Object>)sr, delayTime, unit);
        }
        sr.setFuture(f);
    } catch (RejectedExecutionException ex) {
    
    
        if (parent != null) {
    
    
            parent.remove(sr);
        }
        RxJavaPlugins.onError(ex);
    }
    return sr;
}

这样一来就会在相应的线程中运行 ObserveOnObserver 的 run 方法:

Class ObserveOnObserver {
    
    
......
public void run() {
    
    
    if (outputFused) {
    
    
        drainFused();
    } else {
    
    
        drainNormal();
        }
    }
    ......
}

好吧,在看drainNormal前,我们先看一个函数checkTerminated():

//从名字看是检测是否已终止
  boolean checkTerminated(boolean d, boolean empty, Observersuper T> a) {
    
    
      //1、订阅已取消
      if (cancelled) {
    
    
          //清空队列
          queue.clear();
          return true;
      }
      //2、d其实是done,
      if (d) {
    
    
          //done==ture可能的情况onNext刚被调度完,onError或者onCompele被调用,
          Throwable e = error;
          if (delayError) {
    
    
              //delayError==true时等到队列为空才调用
              if (empty) {
    
    
                  if (e != null) {
    
    
                      a.onError(e);
                  } else {
    
    
                      a.onComplete();
                  }
                  worker.dispose();
                  return true;
              }
          } else {
    
    
              //否则直接调用
              if (e != null) {
    
    
                  queue.clear();
                  a.onError(e);
                  worker.dispose();
                  return true;
              } else
   if (empty) {
    
    
                  a.onComplete();
                  worker.dispose();
                  return true;
              }
          }
      }
      //否则未终结
      return false;
  }

true:1、订阅被取消cancelledtrue,2、donetrue onNext刚被调度完,onError或者onCompele被调用

继续看drainNormal:

void drainNormal() {
    
    
      int missed = 1;
      final SimpleQueue<T> q = queue;
      final Observersuper T> a = actual;
      //Ok,死循环,我们来看下有哪些出口
      for (;;) {
    
    
      //Ok,出口,该方法前面分析的
      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);
                  //停止worker(线程)
                  worker.dispose();
                  return;
              }
              boolean empty = v == null;
              //判断队列是否为空
              if (checkTerminated(d, empty, a)) {
    
    
                  return;
              }
               //没数据退出
              if (empty) {
    
    
                  break;
              }
              //数据下发给下游Obsever,这里支付者onNext,onComplete和onError主要放在了checkTerminated里面回调
              a.onNext(v);
          }
       //保证此时确实有一个 worker.schedule(this);正在被执行,
          missed = addAndGet(-missed);
       //为何要这样做呢?我的理解是保证drainNormal方法被原子性调用,如果执行了addAndGet之后getAndIncrement() == 0就成立了,此时又一个worker.schedule(this);被调用了,那么就不能执行break了
          if (missed == 0) {
    
    
              break;
          }
      }
  }

总结

Ok,看到这里我们基本了解了observeOn的实现流程,同样是老套路,使用装饰者模式,中间Wrapper了我们的Observable和Observer,通过中间增加一个Observable和Observer来实现线程的切换。

猜你喜欢

转载自blog.csdn.net/qq_39431405/article/details/113184120