一、前言

闲来无事,博主有重新翻看了一下jdk1.8版的ThreadPoolExecutor源码,看后写此笔记,画个圈圈,做个记录,这段源码,我看过,到处一游,嘻嘻~~

二、ThreadPoolExecutor数据结构

在ThreadPoolExecutor的内部,主要由BlockingQueue和AbstractQueuedSynchronizer对其提供支持。在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。

三、ThreadPoolExecutor源码分析

类的结构图:

通过查看ThreadPoolExecutor源码的构造函数,corePoolSize(核心线程数),maximumPoolSize(最大线程数),keepAliveTime(当线程池中线程数目>核心线程数,空闲的线程等待任务,即Runnable的时间,超过该时间,该空闲线程将被终止),workQueue(阻塞队列,当线程池线程数>核心线程数时,新来的Runnable任务将放到阻塞队列中,待 Worker获取执行),threadFactory(线程工厂类,创建新的Thread),RejectedExecutionHandler线程拒绝策略,默认是AbortPolicy(抛出RejectedExecutionException异常)

前提:

线程池的五种状态:

RUNNING(线程池正常运行),SHOUDOWN(不接收提交的新Runnable任务,会接着处理阻塞队列里面的任务),STOP(不接收提交的新Runnable任务,不处理阻塞队列里面的任务,中断正在处理的任务)

TIDYING(所有的线程都被终止,执行自定义的钩子方法terminated()

),TERMINATED(线程池终止,终极状态)

接下来,来看线程池提交方法execute(注:submit方法内部也是会调用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:若当前线程池线程数目 < 核心线程数目 ,直接把Runable任务加入新建的Worker中,并启动任务。

2:若线程池正常(ctl == RUNNING),直接创建一个新的Woker,即开启一个新的线程执行Runnable任务。

3: 若线程池线程数目>核心线程数目,并且阻塞队列未满,添加到阻塞队列中,并进行二次判断当前线程池是否还是正常运行的(ctl==Runnable)

becasuse:  若在此时调用了shutdown () or shoutdownNow()方法的话,说明线程池已经发出终止请求,不应该在把新的任务添加到阻塞队列中,并且执行拒绝策略。

4:   线程池允许的最大线程数目>若线程池线程数目>核心线程数目 & 阻塞队列已满, 新建Woker线程执行Runnable任务。

5: 若线程池线程数目>=线程池允许的最大线程数目,对于新提交的任务执行拒绝策略。

在这一连串的逻辑判断中,需要注意一下addWorker这个方法,先上源码:

private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false; for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
} boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get()); if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}

  该方法先判断线程池状态是否发生改变(是否还是RUNNING状态),若不是直接返回false,判断线程池当前线程数目是否大于核心线程数目,超过返回false.

否则新建woker线程,并把新建线程加入到wokers的集合中,启动新建的线程。

启动新建线程会调用Worker实例里面的run方法,run方法中调了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);
}
}

  如果传入的任务不为空,则先执行传入的任务,执行完成后去阻塞队列中获取任务执行。

若传入的任务为空,则直接去阻塞队列里面获取任务执行。

若阻塞队列为空,则runWorker 执行finally代码块。线程池工作线程数目-1,把这个woker从wokers集合移除,并且中断改woker线程。

,     今天就更新到这,下次持续更新ing..................

ThreadPoolExecutor源码分析(一)的更多相关文章

  1. ThreadPoolExecutor源码分析一

           在线程池出现之前,每次需要使用线程,都得创建一个线程.但是,在java的运行环境中,创建一个线程是非常耗费资源和时间的.是否可以把线程重复利用,减少线程的创建次数.基于此,java1.5 ...

  2. Java并发包源码学习之线程池(一)ThreadPoolExecutor源码分析

    Java中使用线程池技术一般都是使用Executors这个工厂类,它提供了非常简单方法来创建各种类型的线程池: public static ExecutorService newFixedThread ...

  3. java多线程系列:ThreadPoolExecutor源码分析

    前言 这篇主要讲述ThreadPoolExecutor的源码分析,贯穿类的创建.任务的添加到线程池的关闭整个流程,让你知其然所以然.希望你可以通过本篇博文知道ThreadPoolExecutor是怎么 ...

  4. ThreadPoolExecutor源码分析-面试问烂了的Java线程池执行流程,如果要问你具体的执行细节,你还会吗?

    Java版本:8u261. 对于Java中的线程池,面试问的最多的就是线程池中各个参数的含义,又或者是线程池执行的流程,彷佛这已成为了固定的模式与套路.但是假如我是面试官,现在我想问一些更细致的问题, ...

  5. Python线程池ThreadPoolExecutor源码分析

    在学习concurrent库时遇到了一些问题,后来搞清楚了,这里记录一下 先看个例子: import time from concurrent.futures import ThreadPoolExe ...

  6. Java核心复习——线程池ThreadPoolExecutor源码分析

    一.线程池的介绍 线程池一种性能优化的重要手段.优化点在于创建线程和销毁线程会带来资源和时间上的消耗,而且线程池可以对线程进行管理,则可以减少这种损耗. 使用线程池的好处如下: 降低资源的消耗 提高响 ...

  7. 线程池ThreadPoolExecutor源码分析

    在阿里编程规约中关于线程池强制了两点,如下: [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程.说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源 ...

  8. ThreadPoolExecutor源码分析二

      接上文,这里继续分析源码 private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPA ...

  9. java.util.concurrent ThreadPoolExecutor源码分析

    实现的接口:Executor, ExecutorService 子类:ScheduledThreadPoolExecutor 这类为java线程池的管理和创建,其中封装好的线程池模型在Executor ...

随机推荐

  1. bzoj 3743 [ Coci 2015 ] Kamp —— 树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 一开始想到了树形DP,处理一下子树中的最小值,向上的最小值,以及子树中的最长路和向上的 ...

  2. MySQL:常见错误01

    ylbtech-MySQL:常见错误01 1.返回顶部 1. [SQL]select * from product_product_tag aLEFT JOIN system_tag b on b.i ...

  3. sql小计合计

    转自:http://www.jb51.net/article/18860.htm 这里介绍sql server2005里面的一个使用实例: CREATE TABLE tb(province nvarc ...

  4. 3个不常用的HTML标签

    html标签众多,在HTML手册里你可以都查到.但有的HTML标签你可能从未使用过.不是因为你欠缺学习精神,而是它们确实用处不大.如果你有探索精神,那就接着往下看吧. 第一个:<abbr> ...

  5. bzoj 1503郁闷的出纳员(splay)

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 11759  Solved: 4163[Submit][Stat ...

  6. 使用protobuf传递网络消息

    1.获取protobuf及相关依赖 新建install_protobuf.bat脚本,粘贴以下代码 ::参考文章 https://github.com/google/protobuf/blob/mas ...

  7. 解决QQ未启用状态,QQ留言图标未启用

    最近由于腾讯升级QQ一些东西,导致QQ图标成未启用状态:如图 解决方法,到腾讯此站点登陆一下即可, http://wp.qq.com/set.html 另外设置 没有保存按钮,如果选择完全公开,到自己 ...

  8. C#之经理评分系统

    PM类,几乎全是属性 using System; using System.Collections.Generic; using System.Linq; using System.Text; usi ...

  9. 几段Python小程序

    程序片段1 第一个需求是需要生成一些随机的时间,例如需要随机生成从一年前到现在的一些时间,刚开始折腾了半天,最后的代码如下: from datetime import timedelta from d ...

  10. Java_Web之宠物管理系统

    使用JSP+servLet实现宠物管理系统,oraC1e11g作为后台数据厍,实现查看宠物和增加宠物的功能由你实现,如图: 其中宠物包栝:狗.猫.鸟.鼠 具体要求及推荐实现步骤 第一步:创建数据库代码 ...