Android

android 线程池的理解

2020-02-13  本文已影响0人  android源码探索

在我看来 理解线程池是非常有必要的,像一些比较出名的开源 框架都用到了线程池, 比如: Okhttp, EventBus等

对于我个人而言,平时对线程池的使用也只是停留在使用层面, 对其原理了解的少之又少,我自己也很好奇,于是花了点时间研究了一下。

带着如下几个问题对线程池进行了解:

  1. ThreadPoolExecutor的工作状态
  2. ThreadPoolExecutor的重要成员变量
  3. 重要成员变量
  4. 常见的线程池

里面大量用到了ReentrantLock, 以及CAS的相关知识, 这一块可以自己脑补一下

ThreadPoolExecutor的工作状态

线程池有5种状态

   private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

每一种状态的具体含义如下(对于这一块只需要记住即可):

线程池的工作状态是什么时候切换呢

通过源码来验证上面的说法:

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

从上面的源码里面看到了如下的一句代码advanceRunState(SHUTDOWN);

 private void advanceRunState(int targetState) {
        // assert targetState == SHUTDOWN || targetState == STOP;
        for (;;) {
            int c = ctl.get();
            if (runStateAtLeast(c, targetState) ||
                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
                break;
        }
    }

这句代码ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
就是通过 CAS的原理进行值 的修改, 而ctlOf方法会计算出真正的状态值

ThreadPoolExecutor的重要成员变量

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

ThreadFactory

线程工厂
其作用是创建线程
如果外面不传入线程工厂, 则默认用源码里面的DefaultThreadFactory

RejectedExecutionHandler

拒绝策略
是在线程池执行excute方法的时候, 如果满足一定条件则会执行其方法

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

从上面的代码分析看到了如下的代码reject(command);
而这个方法是真正的执行拒绝策略里面的方法。

从源码分析 拒绝策略有如下几种:
1)直接抛出异常(AbortPolicy)
默认采用,对拒绝任务抛弃处理,并且抛出RejectedExecutionException异常。

 public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

2)使用调用者的线程来处理(CallerRunsPolicy)
如果当前线程池处于运行状态 ,直接使用当前线程执行任务,如果是终止状态,则直接抛弃。

public static class CallerRunsPolicy implements RejectedExecutionHandler {
        
        public CallerRunsPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

3)直接丢掉这个任务(DiscardPolicy)
对拒绝任务偷偷地抛弃,没有异常信息。查看源码发现他的rejectedExecution ()就是一个空实现。

public static class DiscardPolicy implements RejectedExecutionHandler {
      
        public DiscardPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

4)丢掉最老的任务(DiscardOldestPolicy)
对拒绝任务不抛弃,而是抛弃队列里面等待最久的一个任务,然后把拒绝任务加到队列。

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
      
        public DiscardOldestPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

常见的线程池

这些线程池的创建方法是借助于Excutor工具类来创建的,
其不同之处就是线程池的构造方法的参数不同而已

关联文章:
OkHttp的主线流程详解

关注公众号会不定期更新内容:

qrcode_for_gh_c78cd816dc53_344.jpg
上一篇下一篇

猜你喜欢

热点阅读