android 线程池源码解析

来源:互联网 发布:光盘刻录软件nero 编辑:程序博客网 时间:2024/05/22 10:56

先从俩个概念说起

线程池核心的接口其实是Executor,它有一个execute方法,这个方法的实现在ThreadPoolExecutor中。在ThreadPoolExecutor源码中我们常常能看到这么俩个变量:ctl,worker。

ctl

ctl是什么呢?ctl在源码里的解释是:The main pool control state, ctl, is an atomic integer packing two conceptual fields:
1.workerCount, indicating the effective number of threads
2.runState, indicating whether running, shutting down etc

也就是说ctl是一个原子变量 atomic integer,它将workerCount和runState这俩个值打包在该原子变量里。并且用某种方法打包成一个int值。

workerCount:有效线程的数量,可能会与实际值有所偏差
runState:各个线程的运行状态生命周期,包含:

RUNNING: Accept new tasks and process queued tasks(接收新任务,也执行队列里的任务)

STOP: Don’t accept new tasks, don’t process queued tasks,and interrupt in-progress tasks(不接收,不执行任务,并且中断运行中的任务)

TIDYING: All tasks have terminated, workerCount is zero,the thread transitioning to state TIDYING will run the terminated() hook method(所有任务都结束了,workerCount为0,调用terminated()方法)

TERMINATED: terminated() has completed(terminated()方法调用完成)

转换如下:
* RUNNING -> SHUTDOWN
* On invocation of shutdown(), perhaps implicitly in finalize()
* (RUNNING or SHUTDOWN) -> STOP
* On invocation of shutdownNow()
* SHUTDOWN -> TIDYING
* When both queue and pool are empty
* STOP -> TIDYING
* When pool is empty
* TIDYING -> TERMINATED
* When the terminated() hook method has completed

worker

线程池中的一个线程就是一个Worker对象,Woker中保存着三个对象,分别为:任务要运行的线程,线程任务,完成的任务数。

        /** Thread this worker is running in.  Null if factory fails. */        final Thread thread;        /** Initial task to run.  Possibly null. */        Runnable firstTask;        /** Per-thread task counter */        volatile long completedTasks;

了解了这些概念后,我们看execute方法。

execute

public void execute(Runnable command) {        if (command == null)            throw new NullPointerException();        /*         * Proceed in 3 steps:         *         * 1. 当前运行的线程量少于corePoolSize给定的线程量,则新建线程添加任务,并调用addWoker。并且addWorker中会再次检测RunState和workerCount,以防止错误添加线程。         * 2. 这种情况应该是当活动的有效线程数达到了corePoolSize,此时如果一个任务可以被添加到队列中,然后就会二次检测是否该添加新线程。(因为线程在此期间可能死去)或者我们停止接收任务了。所以需要二次检测。         *         * 3.如果任务队列不能再添加任务了,就开启新线程。如果失败了,意味我们停止接收任务或线程饱和,于是拒绝接收任务。         */        int c = ctl.get();        //核心线程数小于corePoolSize,创建新线程。        if (workerCountOf(c) < corePoolSize) {            if (addWorker(command, true))                return;            c = ctl.get();        }        // 活动线程数 >= corePoolSize        // runState为RUNNING && 队列未满        if (isRunning(c) && workQueue.offer(command)) {            int recheck = ctl.get();            //二次检测,判断线程状态是否为Running(可接收任务状态),不是运行状态则移除已经添加到队列里的command            if (! isRunning(recheck) && remove(command))                reject(command);            else if (workerCountOf(recheck) == 0)             // 这行代码是为了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。            // 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务                addWorker(null, false);        }        // 两种情况:        // 1.非RUNNING状态拒绝新的任务        // 2.队列满了启动新的线程失败(workCount > maximumPoolSize)        else if (!addWorker(command, false))            reject(command);    }

execute方法主要分三步走:
1.当前运行的线程量少于corePoolSize给定的线程量,则新建线程添加任务,并调用addWoker。
2.当目前活动中的线程大于corePoolSize时,先加入到任务队列当中;
3.任务队列满了再去启动新的线程,如果线程数达到最大值就拒绝任务。

原创粉丝点击