ThreadPoolExecutor
它是线程池最核心的类, 这里对核心的方法做简要的剖析(会持续更新),以加深对线程池运行原理的理解。
1. 核心成员变量及相关方法
     // ctl非常重要,用整型表示,共32位,其中**高3位代表线程池状态,低29位代表工作线程数**;
// 线程池状态初始化为RUNNING,工作线程数为0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // 偏移量29
private static final int COUNT_BITS = Integer.SIZE - 3; // 理论最大线程数(约500万)
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // -1左偏移29位(下同),运行中状态,既能接收新提交的任务,又能执行阻塞队列中的任务
private static final int RUNNING = -1 << COUNT_BITS; // 关闭状态,不再接收新提交的任务,但还能继续执行阻塞队列中的任务(调用shutdown()可以进入此状态)
private static final int SHUTDOWN = 0 << COUNT_BITS; // 停止状态,不再接收新提交的任务,也不再执行队列中的任务;而且会尝试中断正在执行的工作线程(调用shutdownNow()可以进入此状态)
private static final int STOP = 1 << COUNT_BITS; // 清理状态,当workCount(工作线程数)为0,且队列也为空时就是此状态
// SHUTDOWN -> TIDYING 线程数为0,队列也为空时会自动进入改状态
// STOP -> TIDYING 线程数为0时,就会自动进入该状态
private static final int TIDYING = 2 << COUNT_BITS; // 终结状态 可以通过调用awaitTermination方法来来等待线程池彻底终结
private static final int TERMINATED = 3 << COUNT_BITS; // 获取线程池运行状态;因为CAPACITY为29个1,取反后是29个0,再通过&运算会取出最高的3位
private static int runStateOf(int c) { return c & ~CAPACITY; } // 获取线程池中线程数;取出最低的29位
private static int workerCountOf(int c) { return c & CAPACITY; } // 将运行状态与线程数拼接起来,共有恰好有32位(因为rs已经左偏移29位了!)
private static int ctlOf(int rs, int wc) { return rs | wc; }

2. 核心构造方法

 /*
* 1. 共有7个参数
* 2. 具体实现不再细说,只简单说下各个作用(就是使用流程)
* corePoolSize: 核心线程数,如果总工作线程数小于核心线程数, 有新任务时则会继续创建新的线程
* maximumPoolSize: 最大线程数,理论上包含了核心线程数和非核心线程数
* keepAliveTime: 一般上(allowCoreThreadTimeOut=false)是指非核心线程没有任务执行的存活时间(可以通过getTask()方法去分析)
* TimeUnit: keepAliveTime的时间单位
* workQueue: 阻塞队列,其中包含有SynchronousQueue, ArrayBlockingQueue, LinkedBlockingQueue; 存放核心线程执行不过来时被提交的任务
* threadFactory: 线程工厂,创建线程的地方
* handler: 拒绝策略,线程池满时会执行该策略rejectedExecution()方法;自带有4种拒绝策略,默认使用抛异常拒绝策略,另有什么都不做策略,用调用者线程执行任务策略,抛弃最旧任务策略
*
* 注意:1. 核心线程和非核心线程只是个逻辑的概念,某个线程被创建后,一开始可能是核心的,到后来会变成非核心的,身份并不固定。(看具体getTask()时会不会得到null)
* 2. 流程归总:当新任务被提交后,当工作线程数小于核心核心线程数时,会继续创建线程来处理此任务,否则会将其放在阻塞队列中;若阻塞队列已满,则会创建线程来处理此任务;若创建线程失败(不小于了最大线程数),则会执行拒绝策略。
*/
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

3. 疑问

1. 线程池属于terminated后,是怎么样释放资源的?terminated()方法是空实现?
2. execute()添加到队列后为什么还要recheck?

Java 并发系列(一) ThreadPoolExecutor源码解析及理解的更多相关文章

  1. Java并发系列[10]----ThreadPoolExecutor源码分析

    在日常的开发调试中,我们经常会直接new一个Thread对象来执行某个任务.这种方式在任务数较少的情况下比较简单实用,但是在并发量较大的场景中却有着致命的缺陷.例如在访问量巨大的网站中,如果每个请求都 ...

  2. 死磕 java同步系列之Phaser源码解析

    问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...

  3. 死磕 java同步系列之ReentrantReadWriteLock源码解析

    问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...

  4. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  5. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  6. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  7. 死磕 java同步系列之CyclicBarrier源码解析——有图有真相

    问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...

  8. 死磕 java同步系列之StampedLock源码解析

    问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWrite ...

  9. 死磕 java同步系列之Semaphore源码解析

    问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaph ...

  10. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

随机推荐

  1. JavaScript停止冒泡例子

    <!DOCTYPE html><html><head><meta charset="utf-8"><title>qypt ...

  2. CentOS7.4+MongoBD3.6.4集群(Shard)部署以及大数据量入库

    前言 mongodb支持自动分片,集群自动的切分数据,做负载均衡.避免上面的分片管理难度.mongodb分片是将集合切合成小块,分散到若干片里面,每个片负责所有数据的一部分.这些块对应用程序来说是透明 ...

  3. EventBus 3.0源码解析

    现在网上讲解EventBus的文章大多数都是针对2.x版本的,比较老旧,本篇文章希望可以给大家在新版本上面带来帮助. EventBus 是专门为Android设计的用于订阅,发布总线的库,用到这个库的 ...

  4. 带你从零学ReactNative开发跨平台App开发[react native SqlLite 终极运用](十二)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  5. 记一次es和mq的netty冲突

      1.今天在服务里面加了 es 6.4的 依赖包后,在预发布测试时候出现了下列的问题 看了 半天,最后发现是 es的 jar包 和 mq的 netty包 有冲突.然后去idea的 jar包依赖里面查 ...

  6. <![CDATA[文本内容]]>

    DTD中的属性类型 全名:character data 在标记CDATA下,所有的标记.实体引用都被忽略,而被XML处理程序一视同仁地当做字符数据看待, CDATA的形式如下: <[CDATA[ ...

  7. elipse安装php

    在用eclipse作为PHP的开发IDE工具时,如果下载的Eclipse不带有PHP功能,则需要我们自己来给Eclipse升级.不过也可以下载eclipseForPHP 在Eclipse的help菜单 ...

  8. web assembly是什么,能干什么

    web assembly混合javascript和另外底层语言编译的模块,共同运行.将js的高级,易用及c/c++的高效底层优势结合起来. 最可能的用处是提供一种可行的方法将原来的c/c++应用por ...

  9. [WinCE] [Win10] Win10 Creator 升级后 Windows Mobile Device Center 不能打开

    运行 services.msc 找到 Windows Mobile 2003-based device connectivity服务,右键属性,Log On选项卡选择 Local System acc ...

  10. mongodb/python3.6/mysql的安装

    1 下载与解压 在官网下载mongodb安装包 tar -zxvf mongodb-linux-x86_64-ubuntu1604-3.4.0.tgz 2 移动安装文件 sudo mv mongodb ...