线程池 ThreadPoolExecutor 类的源码解析:

1:数据结构的分析:

private final BlockingQueue<Runnable> workQueue;  //用于存储未被线程池处理的任务

private final ReentrantLock mainLock = new ReentrantLock(); //维护一个lock来保证线程安全

private final HashSet<Worker> workers = new HashSet<Worker>();

private final Condition termination = mainLock.newCondition(); //通过Condition来进行线程之间的通信

private volatile ThreadFactory threadFactory;  //维护一个线程工厂,用于生成线程

private volatile RejectedExecutionHandler handler; //拒绝任务的句柄对象

private volatile int corePoolSize;  //核心池大小

private volatile int maximumPoolSize;  //最大池的大小

2:构造方法:将用户自定义的参数赋值给成员变量,并且使用默认的线程工厂,默认的任务拒绝

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue) {

this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

Executors.defaultThreadFactory(), defaultHandler);

}

3:下面看看  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);

}

下面主要分析下addWorker这个方法:

//以2种场景为例进行分析:

//1第一次添加任务到线程池中  2 第6次添加  corePoolsize=5

private boolean addWorker(Runnable firstTask, boolean core) { // firstTask就是Runnable任务 core=true

retry:

for (;;) {  //相当于while循环

int c = ctl.get(); //初始换后状态位Running  线程池中任务数为0

int rs = runStateOf(c); //获取线程池的状态 这里是RUNNING

// Check if queue empty only if necessary.

if (rs >= SHUTDOWN &&

! (rs == SHUTDOWN &&

firstTask == null &&

! workQueue.isEmpty()))

return false;

for (;;) { //相当于while循环

int wc = workerCountOf(c); //获取worker数量 wc=0

//判断线程池中线程是否超出了限制,若超出了则返回false

if (wc >= CAPACITY ||

wc >= (core ? corePoolSize : maximumPoolSize))

return false;

//CAS 将c的值+1  操作失败退出循环

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 {

//将传进来的Runnable 任务构建成Worker对象

w = new Worker(firstTask);

//获取worker对应的线程

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());//获取线程池状态 这里是RUNNING

//判断线程池状态

if (rs < SHUTDOWN ||

(rs == SHUTDOWN && firstTask == null)) {

if (t.isAlive()) // precheck that t is startable

throw new IllegalThreadStateException();

//将工作任务添加到workers集合中

workers.add(w);

int s = workers.size();

if (s > largestPoolSize)  //初始化时largestPoolSize=0

largestPoolSize = s; //赋值  largestPoolSize=1

workerAdded = true;  //这里true表明添加成功的标识,后面执行该线程

}

} finally {

mainLock.unlock();

}

if (workerAdded) {

t.start();  //线程开始执行

workerStarted = true;

}

}

} finally {

if (! workerStarted)

addWorkerFailed(w);

}

return workerStarted;

}

下面看看构建 Worker对象的逻辑:

Worker(Runnable firstTask) {

setState(-1); // 设置AQS state=-1

this.firstTask = firstTask; //任务赋值给firstTask全局变量

this.thread = getThreadFactory().newThread(this); //从线程工程创建新的线程

}

当第6次添加的时候

// command Runnable 任务

public void execute(Runnable command) {

if (command == null)

throw new NullPointerException();

int c = ctl.get();  //获取线程池的状态 这里是Running

if (workerCountOf(c) < corePoolSize) {  //这里c的任务数是5 corePoolSize=5

if (addWorker(command, true))

return;

c = ctl.get();

}

// 判断线程池的状态是不是Ruuning  将任务添加到队列中

if (isRunning(c) && workQueue.offer(command)) {//进入这个逻辑

int recheck = ctl.get(); //再次获取ctl对象

if (! isRunning(recheck) && remove(command)) //线程池状态不是Running 或者任务被移除则局拒绝任务

reject(command);

else if (workerCountOf(recheck) == 0)

addWorker(null, false); //添加空任务到worker中

}

else if (!addWorker(command, false))

reject(command);

}

到这里线程池的分析已经结束了;

线程池 ThreadPoolExecutor 类的源码解析的更多相关文章

  1. 线程池 ThreadPoolExecutor 原理及源码笔记

    前言 前面在学习 JUC 源码时,很多代码举例中都使用了线程池 ThreadPoolExecutor,并且在工作中也经常用到线程池,所以现在就一步一步看看,线程池的源码,了解其背后的核心原理. 公众号 ...

  2. Java 多线程(五)—— 线程池基础 之 FutureTask源码解析

    FutureTask是一个支持取消行为的异步任务执行器.该类实现了Future接口的方法. 如: 取消任务执行 查询任务是否执行完成 获取任务执行结果(”get“任务必须得执行完成才能获取结果,否则会 ...

  3. 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)

    在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...

  4. 【高并发】通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程

    核心逻辑概述 ThreadPoolExecutor是Java线程池中最核心的类之一,它能够保证线程池按照正常的业务逻辑执行任务,并通过原子方式更新线程池每个阶段的状态. ThreadPoolExecu ...

  5. Java线程池ThreadPoolExecutor类源码分析

    前面我们在java线程池ThreadPoolExecutor类使用详解中对ThreadPoolExector线程池类的使用进行了详细阐述,这篇文章我们对其具体的源码进行一下分析和总结: 首先我们看下T ...

  6. Java并发指南12:深度解读 java 线程池设计思想及源码实现

    ​深度解读 java 线程池设计思想及源码实现 转自 https://javadoop.com/2017/09/05/java-thread-pool/hmsr=toutiao.io&utm_ ...

  7. 【转载】深度解读 java 线程池设计思想及源码实现

    总览 开篇来一些废话.下图是 java 线程池几个相关类的继承结构: 先简单说说这个继承结构,Executor 位于最顶层,也是最简单的,就一个 execute(Runnable runnable) ...

  8. 线程池ThreadPoolExecutor类的使用

    1.使用线程池的好处? 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第三:提高线程的可管理性 ...

  9. JDBC线程池创建与DBCP源码阅读

    创建数据库连接是一个比较消耗性能的操作,同时在并发量较大的情况下创建过多的连接对服务器形成巨大的压力.对于资源的频繁分配﹑释放所造成的问题,使用连接池技术是一种比较好的解决方式. 在Java中,连接池 ...

随机推荐

  1. jenkins19年最新最管用的汉化

    今天准备学学jenkins ,官方下载了一个最新版本,发现是英文版,网上找个许多汉化方式,几乎都是一种,下载插件 :Locale plugin ....很尴尬,下载完了还是没有汉化 ,是不是jenki ...

  2. STorM32 BGC三轴云台控制板电机驱动电路设计(驱动芯片DRV8313)

    1  序言 相信对云台有兴趣的小伙伴对STorM32 BGC这块云台控制板并不陌生,虽说这块控制板的软件已经不再开源,但是在GitHub上依旧可以找到两三个版本的代码,而硬件呢我们也可以从Olliw( ...

  3. Java学习——反射

    Java学习——反射 摘要:本文主要讲述了什么是反射,使用反射有什么好处,以及如何使用反射. 部分内容来自以下博客: https://www.cnblogs.com/tech-bird/p/35253 ...

  4. deepin添加设置快捷键

    deepin的设置侧边栏没有快捷键需要手动设置,第一步就是要知道设置的命令是什么. 按下start,把其中的"控制中心"发送到桌面,以文本方式打开之,其中的exec字段就是打开设置 ...

  5. Linux文件查找与打包

    一.文件查找 locate与find是经常使用的Linux 命令,刚接触Linux时对这两个命令的使用傻傻的分不清.现在我们来对比一下两个命令到底有哪些区别. 1.1 locate locate让使用 ...

  6. openssl生成随机数

    #include <stdio.h> #include <openssl/bn.h> int main() { BIGNUM *bn; bn = BN_new(); //生成一 ...

  7. ios路线

    http://www.cocoachina.com/ios/20150303/11218.html

  8. openstack Train版 “nova-status upgrade check”报错:Forbidden: Forbidden (HTTP 403)

    部署openstack train版,在部署完nova项目时,进行检查,执行 nova-status upgrade check 返回报错信息如下: [root@controller ~]# nova ...

  9. appium---app输入中文

    在app自动化的过程中,都会遇到输入中文的问题,今天总结下app自动化如何输入中文 app输入中文 在启动app的时候在参数里面添加unicodeKeyboard和resetKeyboard后,运行代 ...

  10. 残差residual VS 误差 error

    https://blog.csdn.net/jmydream/article/details/8764869 In statistics and optimization, statistical e ...