Java线程池状态判断源码_java线程池源码白话分析

1.计算机的基础知识

2fe9f85b6198e2e9d7efffc89e1b2457.png

2.ThreadPoolExecutor简单示例

5e1721c05e07778b24fc35895b73f5f5.png

3.ThreadPoolExecutor属性分析

0765ac8ea53a2ca4ddac0b667252f198.png

467298ff806dd93eda171305c8dc5a99.png

b42e354162ef9bec4073b1415b5f6efe.png

e2613aca3fdba7097dc9b92e4bcc5ba9.png

4.ThreadPoolExecutor构造方法分析

7b74882e9942d3ae1301a5994423b00e.png

5.线程池创建线程顺序分析

98ebf4dac672ff1ce1582c5dc1ac3907.png

当我们执行execute方法提交一个线程的时候,首先会判断当前线程池线程数是否超过核心线程数corePoolSize,若是没有超过,则创建新线程,若是超过,则尝试将Runnable提交到工作队列workQueue中。如果工作队列workQueue没有超过容量,则Runnable提交到工作队列中,如果超过了workQueue的容量,则尝试创建线程。如果此时创建的线程小于最大线程数maximumPoolSize,则创建线程,如果超过了maximumPoolSize,则执行拒绝策列。

6.ThreadPoolExecutor.execute方法分析

b30f64ceb77f72b881c775c5a2f81b11.png

6.1.Worker类分析

每个线程的创建都离不开Worker类,该类完全包装了线程运行的所需要的属性,并提供了初始化线程和从阻塞队列中获取被阻塞的线程并执行的一系列方法。

观察该类代码发现,该类继承了AbstractQueuedSynchronizer并实现了Runnable接口,在创建线程的时候,实际Thread类的构造方法包装的就是Worker类自己(我们知道一般Runnable需要被传入到Thread里面的,如:Thread t = new Thread(runnable), t.start()启动线程)。而从execute方法传过来的Runnable实现只是被封装到了firstTask中,创建出来的Thread在执行的时候,调用的start方法也只是启动了该类的runWorker方法,而真正封装我们执行逻辑的firstTask这个Runnable类在后续调用中也只是执行自己的run方法而已,并不再被Thread封装。

worker为什么要继承AbstractQueuedSynchronizer呢?

因为在runWork的方法内,在调用firstTask处理业务逻辑前,会给代码加上独占锁,加这个独占锁的目的是什么呢?因为我们在调用shutDown方法的时候,并不会终止处于运行中的线程。shutDown方法会根据独占锁来判断当前worker是否正在工作。

8286ca68fe31ca217733db4fd85411c2.png

4c0a268c0325b6739bb15cee80ddc17c.png

f05e83e9474647f1ad98d8da20a4451d.png

6.2.addWorker方法分析

addWorker是创建线程的核心方法,一个worker代表一个线程,而workers这个全局变量可以代表线程池,只有向workers里面添加worker成功的时候,才能代表创建线程成功了。addWorker在执行过程中,会根据线程池状态和线程池数量判断是否能创建线程,创建线程成功会将记录线程池状态和数量的ctl值+1,并将worker加入到workers里面,更新线程池生命周期内线程池线程的最大数量,然后启动线程执行任务。

addWorker的core参数代表是否是在创建核心线程,core为true代表创建核心线程,false代表阻塞队列已满,创建非核心线程。

返回值: true代表创建线程并启动成功,false代表创建线程失败

2acbd8dd82fdeb3794feced25394ae02.png

277bcad2beb185c237bb708b4f6b2203.png

606d0d46808f1a40485ef4565e36c2e4.png

d3653a535357bb0cd785efa58101428e.png

0640a3c42a5d979be8517e56f96f0554.png

6.3.runWorker方法分析

addWorker方法创建线程成功,Worker类的Thread会调用start方法启动自己的run方法,因为Worker类实现了Runnable接口,run方法里面调用了runWorker方法。实际我们execute方法传入的Runnable被封装到了Worker类的firstTask属性里面。然后在runWorker里面调用run方法启动具体的逻辑,注意这里并没用再用Thrad封装Runnable了。线程启动后,会一直运行While循环,循环第一次运行自己传入的Runnable,第二次及之后则通过getTask方法从任务队列种获取具体的Runnable任务了。一旦While循环内发生异常或者getTask返回空,则会调用processWorkerExit执行线程销毁逻辑。getTask方法获取不到具体任务的线程都可被认为是空闲线程。

53a990a051f86b199df5d0b3f9ee3859.png

8e396830ac7a0372f15008533bab9cca.png

a3ce0d8c1ff0824a16c4c593d3436680.png

6.4.getTask方法分析

当getTask返回空的时候,线程可以执行销毁逻辑了。

getTask什么时候返回空?

23a448150c50a44b6133bbf8ab561ccc.png

注意,线程池的allowCoreThreadTimeOut属性会影响getTask方法,导致getTask方法一直阻塞在workQueue.take()这里的,这样就不会销毁线程。

332f7dd8a671be962c73d70805fabfe2.png

2c8ccfd34574e1b12df6958c39216ddf.png

4ac0f96e27a69cde08db4ad49dab83f2.png

6.5.processWorkerExit方法分析

该方法用于执行线程销毁的逻辑。

fa1e1d7e58fafd9ddd4ece6541e85f00.png

006a2c9351fc72ac4a8058be0d2209f5.png

e904fb4ef492ce6d3b350b1569aa450c.png

6.6.tryTerminate方法分析

尝试关闭线程池方法并处理空闲线程,interruptIdleWorkers方法处理空闲线程,设置中断状态。每个线程退出都会单独调用该方法。

4bfd3069b31e656c186a2e7be905f6b7.png

88b1242c4926a07def842e2b062ba466.png

6.7.interruptIdleWorkers方法分析

处理一个空闲线程方法。所有处于执行中的线程都会加锁(w.lock())。上面我们提过,核心线程被take方法阻塞的时候,我们这里设置线程t.interrupt(), 会解除take的阻塞。

8bd43ff9c229564ac46d1e5f7ff0a365.png

6.8.awaitTermination方法分析

该方法是判断线程池状态状态是否是TERMINATED,如果是则直接返回true,否则会await挂起当前线程指定的时间

75aff7904dddfb39fbf55fa470cccf62.png

6.9.shutDown和shutDownNow方法分析

shutDown方法会优雅的关闭线程池,设置线程池状态为SHUTDOWN,已经处于队列中的任务会继续等待执行完。

shutDownNow方法会立即关闭线程池,设置线程池状态为STOP。

2c0dc4854f78e7fcb1de84e588d4c1a8.png

f7ac1f4fbc9ee5dac9cd733c92aba8f3.png

7.ThreadPoolExecutor拒绝策列

默认有以下4中拒绝策列,用户也可以实现RejectedExecutionHandler接口自定义。

a1ca4ac59f341a34888e9fd175fd2207.png

e8b6c4e33f29e736ffe33ae097e63f52.png

8.扩展:改变线程池的初始化过程

如果我们想让线程按核心线程,最大线程,最后再进队列的方式初始化,应该怎么做?

47506202d30da692af90a63997b75b73.png

我们在说execute方法初始化线程池过程中。CASE2:workQueue.offer(command)会将任务加入到队列。所以,我们这里只需要自定义BlockingQueue,改造offer方法,在里面判断,当线程池线程数还未达到最大线程数的时候返回false即可。

Dubbo的EagerThreadPool自定义了一个BlockingQueue,在offer()方法中,如果当前线程池数量小于最大线程池时,直接返回false,这里就达到了调节线程池执行顺序的目的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值