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,这个线程池是一个定时任务的线程池,不断的去回收已经不在使用的线程池。