java
标准化、规范化
java代码风格
【目录】java
编程-java8
编程-java9
编程-java-见过的异常
gradle
编程-java21
编程-java23
编程-java17
编程-java11
【目录】java-web-其它框架
java-vertx
quarkus
javalin
solon
Helidon
【目录】spring家族
spring
springcloud + nacos
consul
springboot启动流程
springboot使用及原理
springcloud
优化springboot
【java高级】
java-多线程-问题记录
java高级-ArrayList
java高级-HashMap
jdk源码解析-TreeMap红黑树
java对象占用多少字节
juc(并发)
ThreadPoolExecutor中ctl变量的理解
ThreadPoolExecutor分析
JVM(java虚拟机)
jvm学习路线
jvm
Java启动参数
debug
java-debug-arthas
java-debug-jdb
高并发/高性能/高可用
设计代码或编写代码时应该考虑的
如何发现系统中的瓶颈?
场景分析
mysql
mysql explain
mysql主从
mysql常见异常
方法论
工作中遇到的问题记录
代码优化
学习的思路
产品
本文档使用 MrDoc 发布
-
+
首页
ThreadPoolExecutor分析
关于线程池的几个问题? 参考: - [ThreadPoolExecutor是怎么去执行一个任务的? - 掘金](https://juejin.cn/post/6854573211892318215) - 它的核心参数是哪些? - 添加任务的逻辑是什么? - 获取并执行任务的逻辑是什么? - 当线程池空闲时怎么删除多余线程的? - 有哪些需要特别注意的点? ## 它的核心参数是哪些 - corePoolSize : 任务队列未达到队列容量时,最大可以同时运行的线程数量。 - maximumPoolSize : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。 - workQueue: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。 - handler :拒绝策略 ## 添加任务的逻辑是什么 1. 如果当前运行的线程数小于核心线程数,那么就会新建一个线程来执行任务。 - (假如corePoolSize=5,此时只有1个任务在运行中,又添加1个任务,还是会创建新线程。) - (假如corePoolSize=5,此时已成功运行过3个任务,又添加1个任务,还是会创建新线程,而不是复用这3个线程。) 2. 如果当前运行的线程数等于或大于核心线程数,但是小于最大线程数,那么就把该任务放入到任务队列里等待执行。 3. 如果向任务队列投放任务失败(任务队列已经满了),但是当前运行的线程数是小于最大线程数的,就新建一个线程来执行任务。 4. 如果当前运行的线程数已经等同于最大线程数了,新建线程将会使当前运行的线程超出最大线程数,那么当前任务会被拒绝,拒绝策略会调用RejectedExecutionHandler.rejectedExecution()方法。 ## 获取并执行任务的逻辑是什么 因为我们提交的任务Runnabale是以`Worker`这个对象去运行。 ```java // 在java.util.concurrent.ThreadPoolExecutor中 private final class Worker extends AbstractQueuedSynchronizer implements Runnable { } ``` java.util.concurrent.ThreadPoolExecutor#addWorker中会创建Worker,并调用Worker#thread的start()方法。 ```java // 在java.util.concurrent.ThreadPoolExecutor中 Worker w = null; try { // 此处创建Worker w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { ... if (workerAdded) { // 此处执行线程t container.start(t); ... } } } // new Worker(firstTask) Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; // 注意:创建的thread中是把当前worker传进去的 this.thread = getThreadFactory().newThread(this); } ``` `container.start(t)`跟着调用到这里。 ```java // 在java.lang.System中 public void start(Thread thread, ThreadContainer container) { thread.start(container); } ``` 最终会调用到Worker的run()方法,别忘记它是一个Runnable。 ``` // 在java.util.concurrent.ThreadPoolExecutor.Worker中 public void run() { runWorker(this); } ``` runWorker会使用firstTask或从workQueue中获取任务去执行。 ```java // 在java.util.concurrent.ThreadPoolExecutor中 private Runnable getTask() { ... for (;;) { int c = ctl.get(); int rs = runStateOf(c); // 当我们调用shutdown()的时候 线程池状态是SHUTDOWN,调用shutdownNow()的时候线程状态是STOP,那么这2种状态是怎么处理阻塞队列里面的任务的呢?代码如下, // 当状态是SHUTDOWN的时候,只有 队列为空的时候 才会返回null // 当状态是STOP的时候,直接返回的null // 说明 SHUTDOWN<STOP if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null; } ... } ``` 最后 用一张流程图,来描述下一个任务从添加到运行结束,经历了哪些方法!  说明:图片来自[ThreadPoolExecutor是怎么去执行一个任务的?前面一遍文章 我们看了下FutureTask的源码,知道了怎 - 掘金](https://juejin.cn/post/6854573211892318215)
我是张三
2025年3月5日 18:56
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
eblog
Markdown文件
分享
链接
类型
密码
更新密码