RxJava之线程切换原理分析

版权声明:未经本人允许,严禁转载 https://blog.csdn.net/lmh_19941113/article/details/85345644

Scheduler翻译成中文就是“调度”的意思,在RxJava里就是线程之间的调度,也就是线程之间的切换。

 从图中可以简单看出,SingleScheduler、ComputationScheduler、IoScheduler、NewThreadScheduler的核心实现就是一个线程池,但该线程池里只会有一个线程,而newScheduledThreadPool是可以延迟、定时执行的,所以我们可以认为SingleScheduler、ComputationScheduler、IoScheduler、NewThreadScheduler的核心实现就是一个可定时、可延迟执行及轮询的特殊线程,下面简称线程。该线程是通过Observable的scheduleDirect方法来提交任务(基本上都是通过此方法来提交任务)。

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

createWorker是一个抽象的方法,在SingleScheduler、ComputationScheduler、IoScheduler、NewThreadScheduler中分别有不同的实现。

1、SingleScheduler原理分析

 createWorker在SingleScheduler中的实现如下,在调用ScheduledWorker的schedule方法将任务交给线程执行。

    public Worker createWorker() {
        //传入一个有且只有一个线程的线程池,就是上面说的特殊线程
        return new ScheduledWorker(executor.get());
    }
   public Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
        ...
        tasks.add(sr);
            try {
            Future<?> f;
            //将任务交给线程执行
            if (delay <= 0L) {
                f = executor.submit((Callable<Object>)sr);
            } else {
                f = executor.schedule((Callable<Object>)sr, delay, unit);
            }
            sr.setFuture(f);
        } catch (RejectedExecutionException ex) {
            ...
    }

 SingleScheduler的原理比较简单,到此就完毕了。但线程是在那里创建的尼?其实在SingleScheduler的构造方法就已经创建了线程。由于SingleScheduler是单例实现,所有SingleScheduler中有且仅有一个线程。 那么当多任务且有耗时操作时,后面的任务就会等待。

    public SingleScheduler(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        executor.lazySet(createExecutor(threadFactory));
    }
    //创建线程池
    static ScheduledExecutorService createExecutor(ThreadFactory threadFactory) {
        return SchedulerPoolFactory.create(threadFactory);
    }
    //是SchedulerPoolFactory中的create方法
    public static ScheduledExecutorService create(ThreadFactory factory) {
        //创建线程池
        final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, factory);
        tryPutIntoPool(PURGE_ENABLED, exec);
        return exec;
    }

2、ComputationScheduler原理分析

 ComputationScheduler就比较麻烦一点了,图中可以看出ComputationScheduler里创建了一组线程。也是在构造方法中创建的,构造方法中调用start方法。

    public ComputationScheduler(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        this.pool = new AtomicReference<FixedSchedulerPool>(NONE);
        start();
    }
    public void start() {
        //MAX_THREADS = cap(Runtime.getRuntime().availableProcessors(), Integer.getInteger(KEY_MAX_THREADS, 0));
        FixedSchedulerPool update = new FixedSchedulerPool(MAX_THREADS, threadFactory);
        //用update替代默认的NONE,NONE中没有任何线程创建
        if (!pool.compareAndSet(NONE, update)) {
            update.shutdown();
        }
    }

 在start中创建了FixedSchedulerPool对象,其中MAX_THREADS是根据Runtime.getRuntime().availableProcessors()计算出来的。来看一下FixedSchedulerPool对象的实现

    static final class FixedSchedulerPool implements SchedulerMultiWorkerSupport {
        final int cores;

        final PoolWorker[] eventLoops;
        long n;

        FixedSchedulerPool(int maxThreads, ThreadFactory threadFactory) {
            // initialize event loops
            this.cores = maxThreads;
            this.eventLoops = new PoolWorker[maxThreads];
            //每个PoolWorker代表一个Executors.newScheduledThreadPool(1, factory)的实现
            for (int i = 0; i < maxThreads; i++) {
                this.eventLoops[i] = new PoolWorker(threadFactory);
            }
        }
        //eventLoops中取出一个线程
        public PoolWorker getEventLoop() {
            int c = cores;
            if (c == 0) {
                return SHUTDOWN_WORKER;
            }
            // simple round robin, improvements to come
            return eventLoops[(int)(n++ % c)];
        }
        ...
        @Override
        public void createWorkers(int number, WorkerCallback callback) {
            int c = cores;
            if (c == 0) {
                for (int i = 0; i < number; i++) {
                    callback.onWorker(i, SHUTDOWN_WORKER);
                }
            } else {
                int index = (int)n % c;
                for (int i = 0; i < number; i++) {
                    callback.onWorker(i, new EventLoopWorker(eventLoops[index]));
                    if (++index == c) {
                        index = 0;
                    }
                }
                n = index;
            }
        }
    }

 在FixedSchedulerPool中创建了一组线程,当有任务时就取出其中一个线程来处理任务,如果任务超出线程数,那么其他任务就会等待。下面来看schedule方法

    public Worker createWorker() {
        //pool.get返回的就是一个FixedSchedulerPool对象
        return new EventLoopWorker(pool.get().getEventLoop());
    }
    public Disposable schedule(@NonNull Runnable action) {
        if (disposed) {
            return EmptyDisposable.INSTANCE;
        }
        return poolWorker.scheduleActual(action, 0, TimeUnit.MILLISECONDS, serial);
    }

 由于poolWorker是NewThreadWorker的子类,所以就调用NewThreadWorker的scheduleActual方法。

    static final class PoolWorker extends NewThreadWorker {
        PoolWorker(ThreadFactory threadFactory) {
            super(threadFactory);
        }
    }
   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;
    }

 在scheduleActual中也是将任务交给给线程执行,由于线程最多有MAX_THREADS个,所以当任务超过MAX_THREADS则会等待,直到其他任务执行完毕释放线程。

3、IoScheduler原理解析

 IoScheduler就有点意思,它有对Worker进行了缓存,实现了一个池CachedWorkerPoolCachedWorkerPool中有一个队列ConcurrentLinkedQueue,它会存储每次使用的线程,同时也在CachedWorkerPool中创建一个线程来不停的扫描(每隔60s扫描一次),判断是否有超时的线程,如果有就从ConcurrentLinkedQueue中将线程移除掉。

扫描二维码关注公众号,回复: 4843995 查看本文章
   static final class CachedWorkerPool implements Runnable {
        //每个线程的存活时间
        private final long keepAliveTime;
        private final ConcurrentLinkedQueue<ThreadWorker> expiringWorkerQueue;
        final CompositeDisposable allWorkers;
        private final ScheduledExecutorService evictorService;
        private final Future<?> evictorTask;
        private final ThreadFactory threadFactory;

        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) {
                //创建一个新的线程,每keepAliveTime(默认是60s)执行一次,扫描是否有超时的线程
                evictor = Executors.newScheduledThreadPool(1, EVICTOR_THREAD_FACTORY);
                task = evictor.scheduleWithFixedDelay(this, this.keepAliveTime, this.keepAliveTime, TimeUnit.NANOSECONDS);
            }
            evictorService = evictor;
            evictorTask = task;
        }

        @Override
        public void run() {
            //每次扫描执行的方法
            evictExpiredWorkers();
        }

        ThreadWorker get() {
            if (allWorkers.isDisposed()) {
                return SHUTDOWN_THREAD_WORKER;
            }
            //判断队列是否为空,不为空则从队列中取出
            while (!expiringWorkerQueue.isEmpty()) {
                ThreadWorker threadWorker = expiringWorkerQueue.poll();
                if (threadWorker != null) {
                    return threadWorker;
                }
            }
            //如果没有缓存的线程,就重新创建
            ThreadWorker w = new ThreadWorker(threadFactory);
            allWorkers.add(w);
            return w;
        }
        //当线程加入到队列中
        void release(ThreadWorker threadWorker) {
            // Refresh expire time before putting worker back in pool
            //更新到期时间
            threadWorker.setExpirationTime(now() + keepAliveTime);
            expiringWorkerQueue.offer(threadWorker);
        }
        //如果线程超出存活时间就移除掉
        void evictExpiredWorkers() {
            if (!expiringWorkerQueue.isEmpty()) {
                long currentTimestamp = now();
                //遍历队列中的所有线程
                for (ThreadWorker threadWorker : expiringWorkerQueue) {
                    if (threadWorker.getExpirationTime() <= currentTimestamp) {
                        if (expiringWorkerQueue.remove(threadWorker)) {
                            allWorkers.remove(threadWorker);
                        }
                    } else {
                        // Queue is ordered with the worker that will expire first in the beginning, so when we
                        // find a non-expired worker we can stop evicting.
                        break;
                    }
                }
            }
        }
        //当前时间
        long now() {
            return System.nanoTime();
        }
        //中断线程
        void shutdown() {
            allWorkers.dispose();
            if (evictorTask != null) {
                evictorTask.cancel(true);
            }
            if (evictorService != null) {
                evictorService.shutdownNow();
            }
        }
    }

 了解CachedWorkerPool后,IoScheduler基本上就没什么难点了,下面再来看createWorker的实现,首先从CachedWorkerPool中取出一个线程,然后在交给这个线程即可。

    public Worker createWorker() {
        return new EventLoopWorker(pool.get());
    }
    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);
        }
    }
    //ThreadWorker继承与NewThreadWorker
    static final class ThreadWorker extends NewThreadWorker {
        //到期时间,到期后该线程就会被移除掉
        private long expirationTime;

        ThreadWorker(ThreadFactory threadFactory) {
            super(threadFactory);
            this.expirationTime = 0L;
        }
        //返回到期时间
        public long getExpirationTime() {
            return expirationTime;
        }
        //设置到期时间
        public void setExpirationTime(long expirationTime) {
            this.expirationTime = expirationTime;
        }
    }

 从上面看出ThreadWorker有一个到期时间,如果到期后就会被销毁,否则继续存在。

4、NewThreadScheduler原理解析

NewThreadScheduler就比较简单,直接来一个任务就创建一个线程。

    public Worker createWorker() {
        return new NewThreadWorker(threadFactory);
    }

 这里直接返回NewThreadWorker,这个类比较简单。

public class NewThreadWorker extends Scheduler.Worker implements Disposable {
    private final ScheduledExecutorService executor;

    volatile boolean disposed;

    public NewThreadWorker(ThreadFactory threadFactory) {
        //创建一个线程,前面已经介绍
        executor = SchedulerPoolFactory.create(threadFactory);
    }

    @NonNull
    @Override
    public Disposable schedule(@NonNull final Runnable run) {
        return schedule(run, 0, null);
    }

    @NonNull
    @Override
    public Disposable schedule(@NonNull final Runnable action, long delayTime, @NonNull TimeUnit unit) {
        if (disposed) {
            return EmptyDisposable.INSTANCE;
        }
        return scheduleActual(action, delayTime, unit, null);
    }

    //提交任务给线程池,也就是前面说的特殊线程
    public Disposable scheduleDirect(final Runnable run, long delayTime, TimeUnit unit) {
        ScheduledDirectTask task = new ScheduledDirectTask(RxJavaPlugins.onSchedule(run));
        try {
            Future<?> f;
            if (delayTime <= 0L) {
                f = executor.submit(task);
            } else {
                f = executor.schedule(task, delayTime, unit);
            }
            task.setFuture(f);
            return task;
        } catch (RejectedExecutionException ex) {
            RxJavaPlugins.onError(ex);
            return EmptyDisposable.INSTANCE;
        }
    }

    //提交任务给线程池,也就是前面说的特殊线程
    public Disposable schedulePeriodicallyDirect(Runnable run, long initialDelay, long period, TimeUnit unit) {
        final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
        if (period <= 0L) {

            InstantPeriodicTask periodicWrapper = new InstantPeriodicTask(decoratedRun, executor);
            try {
                Future<?> f;
                if (initialDelay <= 0L) {
                    f = executor.submit(periodicWrapper);
                } else {
                    f = executor.schedule(periodicWrapper, initialDelay, unit);
                }
                periodicWrapper.setFirst(f);
            } catch (RejectedExecutionException ex) {
                RxJavaPlugins.onError(ex);
                return EmptyDisposable.INSTANCE;
            }

            return periodicWrapper;
        }
        ScheduledDirectPeriodicTask task = new ScheduledDirectPeriodicTask(decoratedRun);
        try {
            Future<?> f = executor.scheduleAtFixedRate(task, initialDelay, period, unit);
            task.setFuture(f);
            return task;
        } catch (RejectedExecutionException ex) {
            RxJavaPlugins.onError(ex);
            return EmptyDisposable.INSTANCE;
        }
    }


    //提交任务给线程池,也就是前面说的特殊线程
    @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;
    }
    //取消线程执行
    @Override
    public void dispose() {
        if (!disposed) {
            disposed = true;
            executor.shutdownNow();
        }
    }

    //停止线程
    public void shutdown() {
        if (!disposed) {
            disposed = true;
            executor.shutdown();
        }
    }
    //是否已经取消
    @Override
    public boolean isDisposed() {
        return disposed;
    }
}

5、TrampolineScheduler原理解析

TrampolineScheduler跟线程没任何关系,默认在任务所在的线程,在Android中,TrampolineScheduler无法做耗时操作,如果要做耗时操作的话则需要开启子线程,否则有可能会产生ANR。TrampolineScheduler主要是实现了PriorityBlockingQueue,它是一个优先级队列,所以TrampolineScheduler仅仅是把任务添加到这个队列并执行。

    public Worker createWorker() {
        return new TrampolineWorker();
    }
  static final class TrampolineWorker extends Scheduler.Worker implements Disposable {
        final PriorityBlockingQueue<TimedRunnable> queue = new PriorityBlockingQueue<TimedRunnable>();

        private final AtomicInteger wip = new AtomicInteger();

        final AtomicInteger counter = new AtomicInteger();

        volatile boolean disposed;
        //添加任务
        @NonNull
        @Override
        public Disposable schedule(@NonNull Runnable action) {
            return enqueue(action, now(TimeUnit.MILLISECONDS));
        }

        @NonNull
        @Override
        public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
            long execTime = now(TimeUnit.MILLISECONDS) + unit.toMillis(delayTime);
            //将任务添加到队列
            return enqueue(new SleepingRunnable(action, this, execTime), execTime);
        }

        Disposable enqueue(Runnable action, long execTime) {
            if (disposed) {
                return EmptyDisposable.INSTANCE;
            }
            final TimedRunnable timedRunnable = new TimedRunnable(action, execTime, counter.incrementAndGet());
            queue.add(timedRunnable);
            //执行任务
            if (wip.getAndIncrement() == 0) {
                int missed = 1;
                for (;;) {
                    for (;;) {
                        if (disposed) {
                            queue.clear();
                            return EmptyDisposable.INSTANCE;
                        }
                        final TimedRunnable polled = queue.poll();
                        if (polled == null) {
                            break;
                        }
                        if (!polled.disposed) {
                            
                            polled.run.run();
                        }
                    }
                    missed = wip.addAndGet(-missed);
                    if (missed == 0) {
                        break;
                    }
                }

                return EmptyDisposable.INSTANCE;
            } else {
                // queue wasn't empty, a parent is already processing so we just add to the end of the queue
                return Disposables.fromRunnable(new AppendToQueueTask(timedRunnable));
            }
        }

        @Override
        public void dispose() {
            disposed = true;
        }

        @Override
        public boolean isDisposed() {
            return disposed;
        }

        final class AppendToQueueTask implements Runnable {
            final TimedRunnable timedRunnable;

            AppendToQueueTask(TimedRunnable timedRunnable) {
                this.timedRunnable = timedRunnable;
            }

            @Override
            public void run() {
                timedRunnable.disposed = true;
                queue.remove(timedRunnable);
            }
        }
    }

6、HandlerScheduler原理分析

HandlerScheduler仅在android中有使用,主要是用于切换主线程,对于Android开发者来说就太熟悉了,就不多叙述。

    public Worker createWorker() {
        return new HandlerWorker(handler, async);
    }

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

        private volatile boolean disposed;

        HandlerWorker(Handler handler, boolean async) {
            this.handler = handler;
            this.async = async;
        }

        @Override
        @SuppressLint("NewApi") // Async will only be true when the API is available to call.
        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.

            if (async) {
                message.setAsynchronous(true);
            }

            handler.sendMessageDelayed(message, 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;
        }

        @Override
        public void dispose() {
            disposed = true;
            handler.removeCallbacksAndMessages(this /* token */);
        }

        @Override
        public boolean isDisposed() {
            return disposed;
        }
    }

7、总结

 关于RxJava中的Schedulers就分析完毕了,这里来总结一下:

  • SingleScheduler:有且仅有一个线程,如果多个任务的话,后面的任务必须等待前面的任务执行完毕,否则无法执行。
  • ComputationScheduler:创建一组线程,但如果任务超过了这一组线程的话,多余的任务则会等待,直到其他任务执行完毕释放线程。
  • IoScheduler:创建了一个池(默认没有任何线程),维持了一组有时效的线程,当无法从池中获取线程时则会创建一个新线程,新线程执行完毕后会放入池中,但如果这个线程超过时效则会从池中移除并销毁。
  • TrampolineScheduler:没有创建任何线程,仅仅实现了一个优先级队列。
  • NewThreadScheduler:每一个任务就创建一个新的线程。
  • HandlerScheduler:RxAndroid独有,主要是切换回主线程做更新UI的操作

猜你喜欢

转载自blog.csdn.net/lmh_19941113/article/details/85345644