从源码剖析RxJava基本工作原理(4),Schedule调度器的实现

45 篇文章 0 订阅
8 篇文章 0 订阅

Schedule调度器

rxJava的调度器还是比较复杂的,继承关系比较复杂不说,而且有很多内部类,绕来绕去的有点恶心。但是嘛,先把图画出来再说,跟着图的路线走,总不会迷路的。
在这里插入图片描述
首先我们使用的schedule的方式就是.subscribeOn(Schedulers.io()) 那么就从这个IO()函数入口去看下,里面是个什么东西,

 @NonNull
 public static Scheduler io() {
     return RxJavaPlugins.onIoScheduler(IO);
 }

再来看下这个IO对象是怎么初始化的,

static {
   SINGLE = RxJavaPlugins.initSingleScheduler(new SingleTask());
   COMPUTATION = RxJavaPlugins.initComputationScheduler(new ComputationTask());
   IO = RxJavaPlugins.initIoScheduler(new IOTask());
   TRAMPOLINE = TrampolineScheduler.instance();
   NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(new NewThreadTask());
}

静态代码块中初始化的,用new IOTask()创建,

static final class IOTask implements Callable<Scheduler> {
     @Override
     public Scheduler call() throws Exception {
         return IoHolder.DEFAULT;
     }
 }
    static final class IoHolder {
        static final Scheduler DEFAULT = new IoScheduler();
    }

IOTask这个类内部返回一个Scheduler对象,由此可见这些对象都是在类被加载之后,初始化的时候就开始生成的,不能被修改。我们调用的 Schedulers.io()是属于单例的,整个应用中只有一例,那其他的 single() newThread() computation() 这些方法都是一样的,是获取的单例。那我们从IoSchedulers开始分析。

我们从构造函数开始分析,看看IoSchedulers空构造函数是怎么做的:

public IoScheduler() {
   this(WORKER_THREAD_FACTORY);
}
public IoScheduler(ThreadFactory threadFactory) {
    this.threadFactory = threadFactory;
    this.pool = new AtomicReference<CachedWorkerPool>(NONE);
    start();
}

里面调用一个线程工厂参数的构造函数,这个线程工厂类的实现我们等下再来看不是很重要,然后再定义一个引用线程池的原子对象,构造参数是NONE,这个NONE看下是啥:

NONE = new CachedWorkerPool(0, null, WORKER_THREAD_FACTORY);
NONE.shutdown();

 CachedWorkerPool(long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) {
      this.keepAliveTime = unit != null ? unit.toNanos(keepAliveTime) : 0L;
      this.expiringWorkerQueue = new ConcurrentLinkedQueue<ThreadWorker>();
      this.allWorkers = new CompositeDisposable();
      this.threadFactory = threadFactory;

      ScheduledExecutorService evictor = null;
      Future<?> task = null;
      if (unit != null) {
          evictor = Executors.newScheduledThreadPool(1, EVICTOR_THREAD_FACTORY);
          task = evictor.scheduleWithFixedDelay(this, this.keepAliveTime, this.keepAliveTime, TimeUnit.NANOSECONDS);
      }
      evictorService = evictor;
      evictorTask = task;
 }

一个容量是0的工作池,在第二个参数为null的情况下,不去定义evictor和evictorTask对象,这两个对象的作用是,evictor线程池内部固定线程为一个,回收已经产生的线程工作者,以及正在工作线程的,task是线程调度的futureTask类型对象,上一章我们已经讲解了这个类的作用和用法了。 evictor.scheduleWithFixedDelay(this, 这句话传入了this,也就是说CachedWorkerPool本身也就是个runnable,具有被线程调度的功能,看下这个runnable的run方法的作用:

   @Override
   public void run() {
       evictExpiredWorkers();
   }
  void evictExpiredWorkers() {
     if (!expiringWorkerQueue.isEmpty()) {
           long currentTimestamp = now();
           for (ThreadWorker threadWorker : expiringWorkerQueue) {
               if (threadWorker.getExpirationTime() <= currentTimestamp) {
                   if (expiringWorkerQueue.remove(threadWorker)) {
                       allWorkers.remove(threadWorker);
                   }
               } else {
                   break;
               }
           }
       }
   }

expiringWorkerQueue 使用完成的线程队列
allWorkers 正在工作的线程队列
看上面的代码意思就是清理超时的已经使用完成的线程。也就是每次构造出来一个CachedWorkerPool这个对象,这个run都会执行一次,应该就是回收不使用的线程的吧。

我们继续看构造函数,里面调用了start方法,里面创建了一个update的工作池,然后将update工作池去更新pool对象,期望是NONE被替换,那么我们就可以知道了,pool只能在构造函数被初始化一次(除了NONE的初始化),start()方法多次调用的话也不会对pool重新赋值,以后每次经过这个判断之后就不会执行。

@Override
public void start() {
    CachedWorkerPool update = new CachedWorkerPool(KEEP_ALIVE_TIME, KEEP_ALIVE_UNIT, threadFactory);
    if (!pool.compareAndSet(NONE, update)) {
        update.shutdown();
    }
}

一般rxJava使用调度器的方法是scheduler.scheduleDirect调用的,那我们进入这个方法看下是怎么实现的,
在这里插入图片描述

@NonNull
public Disposable scheduleDirect(@NonNull Runnable run) {
    return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
    final Worker w = createWorker();

    final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

    DisposeTask task = new DisposeTask(decoratedRun, w);

    w.schedule(task, delay, unit);

    return task;
}

一共分为四步,
(1)生产一个工作者,
(2)包装一下传递进来的runnable对象,
(3)在包装一下生成可disposable的任务task,
(4)使用工作者去调度我们的task任务。
我们的IoScheduler是继承自Scheduler的,所以ioScheduler是有自己的实现方式的:

第一步

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

参数是一个pool.get()返回的是一个ThreadWorker对象,

ThreadWorker get() {
   if (allWorkers.isDisposed()) {
        return SHUTDOWN_THREAD_WORKER;
    }
    while (!expiringWorkerQueue.isEmpty()) {
        ThreadWorker threadWorker = expiringWorkerQueue.poll();
        if (threadWorker != null) {
            return threadWorker;
        }
    }
    // No cached worker found, so create a new one.
    ThreadWorker w = new ThreadWorker(threadFactory);
    allWorkers.add(w);
    return w;
}

可以看到pool生成线程工作者的方式是:先从使用完成的线程队列中取线程工作者,如果没有的话,那么新建一个线程工作者,将其加入到工作者队列中,并且返回这个工作者。
EventLoopWorker是静态内部类,继承自 Scheduler.Worker,实现了schedule方法,看下构造函数:

   EventLoopWorker(CachedWorkerPool pool) {
       this.pool = pool;
       this.tasks = new CompositeDisposable();
       this.threadWorker = pool.get();
   }

那么这个事件循环工作者里面就拥有了线程工作者thradWorker,工作池pool,已经可以disposable的tasks。

第二步
没啥特别的含义省略。
第三步
将我们的runnable封装成DisposeTask,这个task其实也是runnable类,外加上disposable功能,就是可以让这个任务执行可以被取消和中断。
第四步
我们从第一步可以知道w.schedule()方法是外面的eventLoopWorker来实现的,我们去看下这个方法是怎么实现的,

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

首先判断一下当前的状态是不是处于disposed状态,如果是的话,那么之间返回不执行任务,否则,就调用线程工作者去真正的执行任务。我们在进入看看ThreadWorker是怎么实现的:

@NonNull
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
    Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
    ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
    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) {
        if (parent != null) {
            parent.remove(sr);
        }
        RxJavaPlugins.onError(ex);
    }
    return sr;
}

然后我就惊呆了,绕了这么久,就是让task在线程池中执行,醉了。
再来看下这个线程池是什么类型的线程池:

public NewThreadWorker(ThreadFactory threadFactory) {
    executor = SchedulerPoolFactory.create(threadFactory);
}

 public static ScheduledExecutorService create(ThreadFactory factory) {
 	 final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, factory);
     tryPutIntoPool(PURGE_ENABLED, exec);
     return exec;
 }

 static void tryPutIntoPool(boolean purgeEnabled, ScheduledExecutorService exec) {
     if (purgeEnabled && exec instanceof ScheduledThreadPoolExecutor) {
         ScheduledThreadPoolExecutor e = (ScheduledThreadPoolExecutor) exec;
         POOLS.put(e, exec);
     }
 }

我们可以看到这个线程池是有工厂函数创建的并且保存在map集合中,这个线程池是最低保持一个线程的线程池,里面进去看会发现他是一个可延迟可缓存的线程池,缓存数量是整数最大值。

 public static void start() {
        tryStart(PURGE_ENABLED);
    }
 static void tryStart(boolean purgeEnabled) {
     if (purgeEnabled) {
         for (;;) {
             ScheduledExecutorService curr = PURGE_THREAD.get();
             if (curr != null) {
                 return;
             }
             ScheduledExecutorService next = Executors.newScheduledThreadPool(1, new RxThreadFactory("RxSchedulerPurge"));
             if (PURGE_THREAD.compareAndSet(curr, next)) {

                 next.scheduleAtFixedRate(new ScheduledTask(), PURGE_PERIOD_SECONDS, PURGE_PERIOD_SECONDS, TimeUnit.SECONDS);

                 return;
             } else {
                 next.shutdownNow();
             }
         }
     }
 }
 static final class ScheduledTask implements Runnable {
     @Override
     public void run() {
         for (ScheduledThreadPoolExecutor e : new ArrayList<ScheduledThreadPoolExecutor>(POOLS.keySet())) {
             if (e.isShutdown()) {
                 POOLS.remove(e);
             } else {
                 e.purge();
             }
         }
     }
 }

这个工厂会在一开始就会初始化一个线程池用于调度scheduledTask,这个线程池是一个定时任务的线程池,不断的去回收已经不在使用的线程池。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值