Java线程池源码解析

来源:互联网 发布:minimax regret算法f5 编辑:程序博客网 时间:2024/05/16 15:04

Java线程池ThreadPoolExecutor继承了AbstractExecutorService,间接实现了Executor接口。具体的继承关系如下图所示:


常用的Executors其实是个工具类,里面提供了好多静态工厂方法,根据用户选择返回不同的线程池实例。不过一般不推荐直接使用Executors中提供的工厂方法,而是通过ThreadPoolExecutor的方式。

Doug Lea老爷子用一种非常优雅的方式实现了线程池,同时也给出了极其详尽的注释,注释大概有代码行数的两倍,如果不好好研读一下ThreadPoolExecutor的源码,都感觉对不起老爷子。

一、线程池的作用

线程池主要解决两个问题:一方面当执行大量异步任务时候线程池能够提供较好的性能,这是因为线程池中的线程是可以利用的,使用线程池可以降低线程创建和销毁造成的消耗。另一方面线程池提供了一种资源限制和管理的手段,比如当执行一系列任务时候对线程的管理,每个ThreadPoolExecutor也保留了一些基本的统计数据,比如当前线程池完成的任务数目。

二、字段

// ctl是用一个AtomicInteger变量存放两个字段,一共32位// workerCount线程池线程个数。低29位表示。以后如果线程池支持的线程数量变多,可以改成AtomicLong。// runState线程池状态,高3位表示。// 默认是RUNNING状态,线程个数为0private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));// 线程个数掩码位数private static final int COUNT_BITS = Integer.SIZE - 3;// 线程最大个数(低29位)00011111111111111111111111111111private static final int CAPACITY   = (1 << COUNT_BITS) - 1;// (高3位):111:接受新任务并且处理阻塞队列里的任务private static final int RUNNING    = -1 << COUNT_BITS;// (高3位):000:不接受新任务但是处理阻塞队列里的任务private static final int SHUTDOWN   =  0 << COUNT_BITS;// (高3位):001:不接受新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务private static final int STOP       =  1 << COUNT_BITS;// (高3位):010:所有任务都执行完(包含阻塞队列任务)当前线程池活动线程为0,将要调用terminated方法private static final int TIDYING    =  2 << COUNT_BITS;// (高3位):011:终止状态。terminated方法调用完成以后的状态private static final int TERMINATED =  3 << COUNT_BITS;// 获取高3位 线程状态private static int runStateOf(int c)     { return c & ~CAPACITY; }// 获取低29位 线程个数private static int workerCountOf(int c)  { return c & CAPACITY; }// 拼装ctl新值,线程状态与线程个数private static int ctlOf(int rs, int wc) { return rs | wc; }

线程池状态转换:

RUNNING -> SHUTDOWN

显式调用shutdown()方法,或者隐式调用了finalize(),它里面调用了shutdown()方法。

(RUNNING or SHUTDOWN) -> STOP

显式调用shutdownNow()方法

SHUTDOWN -> TIDYING

当线程池和任务队列都为空的时候

STOP -> TIDYING

当线程池为空的时候

TIDYING -> TERMINATED

当terminated() hook方法执行完成时

三、构造方法

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,    TimeUnit unit,    BlockingQueue<Runnable> workQueue,    ThreadFactory threadFactory,    RejectedExecutionHandler handler);

线程池的构造方法共有7个参数,分别为:

corePoolSize:线程池核心线程个数;

maximunPoolSize:线程池最大线程数量;

keeyAliveTime:如果当前线程池中的线程数量比核心线程数量要多,并且是闲置状态的话,这些闲置的线程能存活的最大时间;

TimeUnit,存活时间的时间单位;

workQueue:用于保存待执行的任务的阻塞队列;

ThreadFactory:创建线程的工厂;

RejectedExecutionHandler:拒绝策略,当队列满了并且线程个数达到maximunPoolSize后采取的策略,比如AbortPolicy(抛出异常),CallerRunsPolicy(使用调用者所在线程来运行任务),DiscardOldestPolicy(调用poll丢弃一个任务,执行当前任务),DiscardPolicy(默默丢弃,不抛出异常)

四、内部类Worker

Worker继承AQS和Runnable是具体承载任务的对象,Worker继承了AQS自己实现了简单的不可重入独占锁,其中status=0标示锁未被获取状态也就是未被锁住的状态,state=1标示锁已经被获取的状态也就是锁住的状态。

五、核心方法

1、execute()方法:添加任务到线程池

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

(1)当前线程池中的核心线程数还小于corePoolSize,那就再创建一个核心线程;

(2)如果任务被成功添加进等待队列(线程池处于RUNNING状态且等待队列未满),如果当前线程池状态不是RUNNING则从队列删除任务,并执行拒绝策略,如果当前线程池线程数为空,则添加一个线程;

(3)如果队列满了,则新增线程,如果新增线程失败则执行拒绝策略。

2、runWorker()方法:执行任务

final void runWorker(Worker w) {    Thread wt = Thread.currentThread();    Runnable task = w.firstTask;    w.firstTask = null;    w.unlock(); // allow interrupts    boolean completedAbruptly = true;    try {        while (task != null || (task = getTask()) != null) {            w.lock();            if ((runStateAtLeast(ctl.get(), STOP) ||                 (Thread.interrupted() &&                  runStateAtLeast(ctl.get(), STOP))) &&                !wt.isInterrupted())                wt.interrupt();            try {                beforeExecute(wt, task);                Throwable thrown = null;                try {                    task.run();                } catch (RuntimeException x) {                    thrown = x; throw x;                } catch (Error x) {                    thrown = x; throw x;                } catch (Throwable x) {                    thrown = x; throw new Error(x);                } finally {                    afterExecute(task, thrown);                }            } finally {                task = null;                w.completedTasks++;                w.unlock();            }        }        completedAbruptly = false;    } finally {        processWorkerExit(w, completedAbruptly);    }}

可以使用beforeExecute和afterExecute这两个方法去监控任务的执行情况,这些方法在ThreadPoolExecutor里都是空方法,可以重写这些方法来实现线程池的监控。线程的逻辑是不断地执行一个循环,去调用getTask方法来获得任务。






阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老奥拓快乐王子通病 奥拓自动挡怎么样 长安铃木奥拓多少钱 新款奥拓怎么样 奥拓电子怎么样 奥拓全险一年多少钱 二手新款奥拓多少钱 铃木奥拓车怎么样 小奥拓车多少钱 新款奥拓图片 奥拓汽车价格 奥拓报废多少钱 二手奥拓车价格 13年新款奥拓 奥拓和雨燕哪个好 奥拓老年代步车 老奥拓汽车报价 奥拓新款报价 自动挡奥拓价格 奥拓是什么牌子 奥拓自动挡报价 二手奥拓怎么样 雨燕和奥拓哪个好 奥拓轿车价格 奥拓改装天然气 2013新款奥拓 铃木奥拓新款报价 奥拓新款汽车 铃木奥拓口碑 新明锐价格 新明锐报价 长安铃木奥拓报价 奥拓电动汽车报价 老款奥拓汽车报价 奥拓汽车怎么样 aotuo aito 长安铃木新奥拓图片 奥拓赛汽车图片 奥扩 铃木越野车