参考:https://www.cnblogs.com/liuyun1995/p/9305273.html

ThreadPoolExecutor1 executorService1 = new ThreadPoolExecutor1(3)

线程池的线程是懒初始化的,第一个任务来了创建一下执行,执行完了等待队列,只会从队列拿任务,不会直接接受任务。第二个任务来了,不会加到队列,也不会给第一个线程去执行,而是创建一个线程执行,第二个线程执行完了等待队列。第三个任务来了,即使前面2个线程执行完了,也不会给前面2个线程执行,而是创建第三个线程去执行,执行完了就等队列。第四个任务来了,不会直接给线程去执行,而是加到队列,让前3个线程去队列取任务。

Worker里面封装了这个任务,并且里面有一个线程池的线程,总共3个Worker,3个任务(3个第一个任务),3个线程。线程run时候就开一个线程去执行Worker里的第一个任务,线程Thread run的时候,是开一个线程池的线程,然后Thread里面的Runnable的run方法在这个线程里面执行,所以Worker要设置成这个Thread的Runnable,就是Worker的run方法在这个线程里面执行(转调外部类的runWorker方法,把worker传进去)runWorker方法就在这个线程里面执行。Worker里面仅仅保存的是这个worker的第一个任务,第一个任务执行完会死循环执行queue队列的任务。

Worker是作为一个Runnable存在于线程池的线程Thread中的,所有Worker的方法都在这个线程中执行(多个线程执行Worker类的相同方法)。runWorker执行的时候,worker w成为了这个线程的局部变量,w.lock();w.unlock(); 多线程执行同一个方法不要紧,只要不是使用共享变量就没事。由于w不是共享变量,一个线程一个局部变量w,所以不会抢锁一个线程的Worler w不会跑到另一个线程里面去,所以是单线程访问的。

executorService.execute(new Runnable() {} = firstTask);
Worker w = new Worker(firstTask);
Worker(Runnable firstTask) {
setState(-);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}

一个线程池线程中一个Runnable(Worker),这个Runnable(Worker)不仅仅执行第一个任务还执行队列的任务,这个Runnable一直不会退出。

所有的任务都在这个线程里面执行,所有的任务都由这个worker执行。

要想w.lock();w.unlock();有线程抢锁,那么一个worker就要被设置到多个线程池的线程去,一个Worker成为多个线程的Runnable,多个线程同时执行时候,这一个Runnable在多个线程中执行,成为多个线程的局部变量w,w.lock();w.unlock();就会出现多线程抢锁。但是不行,

线程跟worker是一对一的关系,通过Runnable建立起来的。

其他线程调用中断interrupt相关方法时候,会从workers中获取一个worker,此时worker w就存在于另一个线程中了,就会多个线程使用这个worker w了。此时锁就有意义了。

Worker初始化时候,只会在一个线程池的线程中,是单线程。但是其他线程可以从workers里面获取这个worker,就是多线程访问。

线程池的所有线程全保存在workers里面的worker里面的thread上面。

超过3个任务进来, 不会创建线程,而是直接丢到队列里面去,然后流程执行完。

Worker继承AQS也就是一个ReentantLock,不同的线程调用worker w的lock和unlock方法可以实现锁的功能,不同的线程可以锁住不同的代码段。


当一个任务提交至线程池之后,

1. 线程池首先判断核心线程池里的线程是否已经满了。如果不是,则创建一个新的工作线程来执行任务。否则进入2.

2. 判断工作队列是否已经满了,倘若还没有满,将线程放入工作队列。否则进入3.

3. 判断线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行。如果线程池满了,则交给饱和策略来处理任务。

RUNNING:111   SHUTDOWN:000    STOP:001    TIDYING:010    TERMINATED:011

SHUTDOWN = 0,STOP|TIDYING|TERMINATED > 0,RUNNING < 0

新建一个线程池时它的状态为Running,这时它不断的从外部接收并处理任务,当处理不过来时它会把任务放到任务队列中;

之后我们可能会调用shutdown()来终止线程池,这时线程池的状态从Running转为Shutdown,它开始拒绝接收从外部传过来的任务,但是会继续处理完任务队列中的任务;

我们也可能调用shutdownNow()来立刻停止线程池,这时线程池的状态从Running转为Stop,然后它会快速排空任务队列中的任务并转到Tidying状态,处于该状态的线程池需要执行terminated()来做相关的扫尾工作,

执行完terminated()之后线程池就转为Terminated状态,表示线程池已终止。这些状态的转换图如下所示。

  • RUNNING:接受新任务并且处理阻塞队列里的任务
  • SHUTDOWN:拒绝新任务但是处理阻塞队列里的任务
  • STOP:拒绝新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务
  • TIDYING:所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为0,将要调用terminated方法
  • TERMINATED:终止状态。terminated方法调用完成以后的状态

线程池状态转换

RUNNING -> SHUTDOWN

显式调用shutdown()方法, 或者隐式调用了finalize()方法

(RUNNING or SHUTDOWN) -> STOP

显式调用shutdownNow()方法

SHUTDOWN -> TIDYING

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

STOP -> TIDYING

当线程池为空的时候

TIDYING -> TERMINATED

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

corePoolSize:corePoolSize –> workQueue –> maximumPoolSize。如果运行的线程少于 corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的;当线程池中的线程数量大于等于 corePoolSize 且小于 maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务;当运行的线程数量大于等于maximumPoolSize,这时如果workQueue已经满了,则通过handler所指定的策略来处理任务;一般来说都会把corePoolSize和maximumPoolSize,设置为一样,这样的话,能够减少线程创建的消耗,直接往阻塞队列中取就可以了.

如果采用无界队列,那么maximumPoolSize将会失去作用,此时一般corePoolSize和maximumPoolSize,设置为一样;

keepAliveTime:线程池维护线程所允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;


首先是RUNNING状态,然后进入SHUTDOWN和STOP状态,进入SHUTDOWN和STOP状态还有去调整(处理队列任务),调整完最后进入TERMINATED状态。

ctl从11100000000000000000000000000000=-536870912开始,慢慢加1,一直越来越大,最后=111111111111111111111111=-1

worker线程数量最大2^29-1=536870911个,就不能再增加了,所以ctl的范围是(-536870912,-1)一直小于0。

当线程池状态改变时候,改变的是前3位,后29位不变,处于别的状态时候继续使用,原来是1110001101010101010(RUNNING状态),变成SHUTDWON之后ctl是0000001101010101010(SHUTDOWN态),变成STOP之后是0010001101010101010(STOP状态),变成TIDYING后是0100001101010101010(TIDYING态),变成TERMINATED后是0110001101010101010(TERMINATED态)

RUNNING值 < SHUTDOWN值 < STOP值 < TIDYING值 < TERMINATED值,大小顺序,基本符合状态的流转过程。

RUNNING值 <= RUNNING态ctl值 < SHUTDOWN值 <= SHUTDOWN态ctl值 < STOP值 <= STOP态ctl值 < TIDYING值 <= TIDYING态ctl值 < TERMINATED值 <=TERMINATED态ctl值。

每个状态的ctl值大于等于这个状态的标称值,小于下一个标称值。标称值是全0的临界值。rs后面全是0,ctl后面不是0。rs可以用=,ctl不能用=,ctl只能用大于小于。ctl和rs用大于小于判断得到的状态是一个区间值,是多个可能的值。

1.处于正常状态的ctl,ctl=111xxxxxxxx,rs=runStateOf(ctl)=RUNNING=111 0000000000000000,RUNNING<=ctl<SHUTDOWN

2.处于关闭状态的ctl,ctl=000xxxxxxxx,rs=runStateOf(ctl)=SHUTDOWN=000 0000000000000000,SHUTDOWN<=ctl<STOP

3.处于停止状态的ctl,ctl=001xxxxxxxx,rs=runStateOf(ctl)=STOP=001 0000000000000000 ,STOP<=ctl<TIDYING

4.处于调整中的ctl,ctl=010xxxxxxxx,rs=runStateOf(ctl)=TIDYING=010 0000000000000000,TIDYING<=ctl<TERMINATED

5.处于调整完毕的ctl,ctl=011xxxxxxxx,rs=runStateOf(ctl)=TERMINATED=011 0000000000000000 ,TERMINATED<=ctl<=2^31-1

rs只能等于111 0000000000000000(RUNNING),000 0000000000000000(SHUTDOWN),001 0000000000000000(STOP),010 0000000000000000(TIDYING),011 0000000000000000(TERMINATED)

rs>=RUNNING,ctl,rs有5种状态。

rs>=SHUTDOWN,ctl,rs有4种状态。

rs>=STOP,ctl,rs有3种状态。

rs>=TIDYING,ctl,rs有2种状态。

rs>=TERMINATED,ctl,rs有1种状态。

ctl>=RUNNING,ctl,rs有5种状态。

ctl>=SHUTDOWN,ctl,rs有4种状态。

ctl>=STOP,ctl,rs有3种状态。

ctl>=TIDYING,ctl,rs有2种状态。

ctl>=TERMINATED,ctl,rs有1种状态。

int rs = runStateOf(c);//前3位不变,后面29位=0

//c处于RUNNING状态,c=111xxxxxxxxx,rs=111 0000000000000000(RUNNING)

//c处于SHUTDOWN状态,c=000xxxxxxxxx,rs=000 0000000000000000(SHUTDOWN)

//c处于STOP状态,c=001xxxxxxxxx,rs=001 0000000000000000(STOP)

//c处于TIDYING状态,c=010xxxxxxxxx,rs=010 0000000000000000(TIDYING)

//c处于TERMINATED状态,c=011xxxxxxxxx,rs=011 0000000000000000(TERMINATED)

正常运行小于0,SHUTDOWN=0,其他STOP,TIDYING,TERMINATED都是大于0

//C的低29位,跟00011111 11111111 11111111 11111111比较,低29位表示线程池中线程数,最大2^29-1。
private static int workerCountOf(int c) {//对2^29取余,ctl加了多少次1,最大加2^29-1次。表示多少个worker已经在运行了。
return c & CAPACITY;//00011111 11111111 11111111 11111111
} // C的高3位,高3位表示线程池的运行状态。111RUNNING:运行中,接受新任务处理队列中的任务。
//000SHUTDOWN:不接收新任务处理队列中的任务; 001STOP:不接收新任务也不处理队列中的任务还中断正在运行的任务;
//010TIDYING:所有的任务都已经终止;011TERMINATED:terminated()方法已经执行完成
private static int runStateOf(int c) {
return c & ~CAPACITY;//11100000 00000000 00000000 00000000
}

ThreadPoolExecutor源码1的更多相关文章

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

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

  2. ThreadPoolExecutor系列<三、ThreadPoolExecutor 源码解析>

    本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7681826.html 在源码解析前,需要先理清线程池控制的运行状态 ...

  3. ThreadPoolExecutor系列三——ThreadPoolExecutor 源码解析

    ThreadPoolExecutor 源码解析 本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7681826.htm ...

  4. 【Java并发编程】21、线程池ThreadPoolExecutor源码解析

    一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...

  5. ThreadPoolExecutor源码解读

    1. 背景与简介 在Java中异步任务的处理,我们通常会使用Executor框架,而ThreadPoolExecutor是JUC为我们提供的线程池实现. 线程池的优点在于规避线程的频繁创建,对线程资源 ...

  6. ThreadPoolExecutor 源码阅读

    目录 ThreadPoolExecutor 源码阅读 Executor 框架 Executor ExecutorService AbstractExecutorService 构造器 状态 Worke ...

  7. Java并发之线程池ThreadPoolExecutor源码分析学习

    线程池学习 以下所有内容以及源码分析都是基于JDK1.8的,请知悉. 我写博客就真的比较没有顺序了,这可能跟我的学习方式有关,我自己也觉得这样挺不好的,但是没办法说服自己去改变,所以也只能这样想到什么 ...

  8. 【详解】ThreadPoolExecutor源码阅读(三)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) 线程数量的 ...

  9. 【详解】ThreadPoolExecutor源码阅读(二)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) AQS在W ...

  10. 【详解】ThreadPoolExecutor源码阅读(一)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) 工作原理简 ...

随机推荐

  1. Markdown温故知新(0):导航目录

    Markdown温故知新(0):导航目录 Markdown温故知新(1):Markdown面面观 Markdown温故知新(2):详解七大标准语法 Markdown温故知新(3):六个实用扩展语法 M ...

  2. Message "'OFFSET' 附近有语法错误。\r\n在 FETCH 语句中选项 NEXT 的用法无效。" 解决办法 EntityFrameworkCore

    由于新版的EntityFrameworkCore默认使用的是SqlServer2012或以上版本的Sql语法分页,来提高性能. 所以使用数据库的版本如果低于2012(如Sqlserver2008)需要 ...

  3. 易百教程人工智能python补充-NLTK包

    自然语言处理(NLP)是指使用诸如英语之类的自然语言与智能系统进行通信的AI方法. 如果您希望智能系统(如机器人)按照您的指示执行操作,希望听取基于对话的临床专家系统的决策时,则需要处理自然语言. N ...

  4. java 手写 jvm高性能缓存

    java 手写 jvm高性能缓存,键值对存储,队列存储,存储超时设置 缓存接口 package com.ws.commons.cache; import java.util.function.Func ...

  5. Vue.js最佳实践--VueRouter的beforeEnter与beforeRouteLeave冲突解决

    用Vue做应用管理系统,通常会在离开某个页面的时候,需要检测用户是否有修改,询问用户需要不需要保存之类的需求 这时候,在读VueRouter文档:组件内的守卫 的时候,发现beforeRouteLea ...

  6. 5G:为人工智能与智能制造赋能

    近几年,全球有两大科技领域越来越热:一个是人工智能,另一个是5G.两者都是能够改变时代.改变社会.改变经济的颠覆性技术.目前,我国已经发放了四张5G牌照,5G产业处在爆发前夜的阶段:人工智能方面,业界 ...

  7. Hexo主题开发

    序章 想要一个自己的知识管理系统,用了 Hexo ,但是没有发现自己心仪的主题,就自己做了一个.本文记录了制作的全过程.本人编码功底和前端知识并不是特别雄厚,希望能由此文引出各路大神的兴趣,以后制作出 ...

  8. mysql语法之union

    UNION的语法结构: SELECT ... UNION [ ALL | DISTINCT ]  SELECT .... [ UNION [ ALL | DISTINCT ] SELECT ..... ...

  9. mybatis 模糊查询 mapper.xml的写法

    1. sql中字符串拼接 SELECT * FROM tableName WHERE name LIKE CONCAT(CONCAT('%', #{text}), '%'); 2. 使用 ${...} ...

  10. 初识PIXI.js

    由于项目需要接触到PIXI这个框架,故开始了一顿打头操作 由于目前PIXI的文档还是很少,而且大多数是英文文档这里提供几个PIXI的demo和文档 demo: http://47.99.120.179 ...