Java线程池-执行顺序

文章目录

参考文档: https://javaj.blog.csdn.net/article/details/155262391

这篇博客讲解的很清楚了,我这里主要是把里面内容实践了下,在结合源码总结下。

一、代码地址

https://gitee.com/YaChiXiaoLiao/nkw/blob/master/src/threadPool/ExecutorsDemo.java

二、线程池核心参数

7个核心参数。 我们可以通过这个Demo点进去详细查看。

java 复制代码
 // 1. 固定线程池 核心线程数=最大线程数,无空闲线程超时
        //场景: 任务量稳定,避免线程频繁创建销毁
        ExecutorService fixedPool = Executors.newFixedThreadPool(3); //3个固定工人


拒绝策略有四种,分别是ThreadPoolExecutor类的四个静态内部类:

三、线程池执行顺序

那么线程池到底怎么执行呢?这就跟上面的7个参数密切相关了。先说结论,然后我们根据代码示例运行结果来验证。

假设这7个参数设置的值对应如下:

java 复制代码
int corePoolSize,			3
int maximumPoolSize,	5
long keepAliveTime,   1
TimeUnit unit,				秒
BlockingQueue<Runnable> workQueue,   new ArrayBlockingQueue<>(10)
ThreadFactory threadFactory,  一个工厂
RejectedExecutionHandler handle  new ThreadPoolExecutor.CallerRunsPolicy()

假设来了16个任务,那么任务1、2、3会直接分配给3个corePoolSize去执行;任务4~13这10个任务会直接进入队列------ArrayBlockingQueue里,因为队列可以容纳10个任务(此时3个corePoolSize的任务都在进行中,如果期间有完成的,会从队列里拿而非直接抢断新的任务(新任务还是会进队列等待)),这里先简化为都在执行。然后队列已满,来的第14、15个任务如何处理?此时会比较corePoolSize和maximumPoolSize,发现corePoolSize=3 < maximumPoolSize=5, 那么好有2个空闲,此时会再创建2个临时线程,所以任务14、任务15交给了刚新创建的2个临时线程处理;好了,第16个任务来了,发现前面15个线程都在处理中,且队列已经放不下了,已经超过了处理能力上限,就按照CallerRunsPolicy策略来处理,这个策略含义是交给调用方的线程去处理,所以第16个任务会是主线程处理,而非线程池里的非守护线程处理。

看下AI的总结:

java 复制代码
线程池的任务分配 + 空闲线程处理逻辑是 "两步走",这是你场景的核心依据:

步骤 1:新任务提交时的分配逻辑(优先级)
当提交一个新任务时,线程池会按以下顺序判断:
核心线程池是否有空闲? → 有则核心线程执行新任务;
核心线程池已满? → 检查任务队列是否未满 → 未满则新任务入队列;
队列也满了? → 检查是否达到最大线程数 → 未到则创建非核心线程执行新任务;
已到最大线程数? → 执行拒绝策略。

步骤 2:核心线程空闲后的任务获取逻辑
核心线程执行完当前任务后,不会 "主动抢新提交的任务",而是优先从任务队列中获取等待的任务执行(这是线程池 "复用核心线程、减少线程创建开销" 的设计核心)。

四、代码示例

1、示例1-ExecutorsDemo

运行结果:

java 复制代码
主线程:创建第1 个任务
线程池中的异步任务执行【开始】
主线程循环到:1
主线程:创建第2 个任务
主线程循环到:2
主线程:创建第3 个任务
线程池中的异步任务执行【开始】
主线程循环到:3
主线程:创建第4 个任务
线程池中的异步任务执行【开始】
主线程循环到:4
主线程:创建第5 个任务
主线程循环到:5
线程 pool-1-thread-1  处理任务1
线程 pool-1-thread-3  处理任务3
线程 pool-1-thread-2  处理任务2
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【开始】
线程 pool-1-thread-3  处理任务5
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【开始】
线程 pool-1-thread-2  处理任务4
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【完毕】

1、注意主线程和非守护线程执行顺序;

观察发现execute里的日志:"线程池中的异步任务执行【开始】"的顺序很奇怪。按理说应该和非守护线程一起异步执行,但实际结果却基本和主线程一同打印了出来。

2、3个核心线程执行之后,其他2个任务应该是进入队列里。2、3执行完毕后继续从队列里取,执行4、5。4、5在队列里虽然有顺序,但是线程竞争拿的时候就未必会按照队列顺序拿,所以这里出现了先处理任务5,后处理任务4的情况。

所以多执行几次,每次效果不一样的:

java 复制代码
主线程:创建第1 个任务
线程池中的异步任务执行【开始】
主线程循环到:1
主线程:创建第2 个任务
主线程循环到:2
主线程:创建第3 个任务
线程池中的异步任务执行【开始】
主线程循环到:3
主线程:创建第4 个任务
线程池中的异步任务执行【开始】
主线程循环到:4
主线程:创建第5 个任务
主线程循环到:5
线程 pool-1-thread-2  处理任务2
线程 pool-1-thread-1  处理任务1
线程 pool-1-thread-3  处理任务3
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【开始】
线程池中的异步任务执行【完毕】
线程 pool-1-thread-1  处理任务4
线程池中的异步任务执行【开始】
线程 pool-1-thread-2  处理任务5
线程池中的异步任务执行【完毕】
线程池中的异步任务执行【完毕】

2、示例2-ThreadPoolExecutorDemo

执行结果:

java 复制代码
线程-【业务线程池-线程-3】处理任务3
线程-【业务线程池-线程-4】处理任务14
线程-【业务线程池-线程-1】处理任务1
线程-【业务线程池-线程-2】处理任务2
线程-【业务线程池-线程-5】处理任务15
线程-【main】处理任务16
JVM退出,线程池优雅关闭
线程-【业务线程池-线程-5】处理任务6
线程-【业务线程池-线程-1】处理任务4
线程-【业务线程池-线程-4】处理任务7
线程-【业务线程池-线程-2】处理任务8
线程-【业务线程池-线程-3】处理任务5
线程-【业务线程池-线程-1】处理任务9
线程-【业务线程池-线程-5】处理任务10
线程-【业务线程池-线程-2】处理任务11
线程-【业务线程池-线程-3】处理任务12
线程-【业务线程池-线程-4】处理任务13

1)这个可以充分证明线程池的执行顺序,任务14、15是在队列满了后,发现核心线程3<最大线程5,所以创建了2个非核心线程来处理。

2)jvm虽然退出,但是非守护线程还可以继续执行;

3)主线程处理了任务16,是按照new ThreadPoolExecutor.CallerRunsPolicy() //拒绝策略 :提交者自己执行(这里就是main方法)来执行的。且顺序会变化。

多次执行发现:

java 复制代码
线程-【main】处理任务16
线程-【业务线程池-线程-3】处理任务3
线程-【业务线程池-线程-1】处理任务1
线程-【业务线程池-线程-4】处理任务14
线程-【业务线程池-线程-5】处理任务15
线程-【业务线程池-线程-2】处理任务2
JVM退出,线程池优雅关闭
线程-【业务线程池-线程-1】处理任务5
线程-【业务线程池-线程-3】处理任务4
线程-【业务线程池-线程-4】处理任务6
线程-【业务线程池-线程-5】处理任务7
线程-【业务线程池-线程-2】处理任务8
线程-【业务线程池-线程-1】处理任务9
线程-【业务线程池-线程-5】处理任务11
线程-【业务线程池-线程-4】处理任务10
线程-【业务线程池-线程-3】处理任务12
线程-【业务线程池-线程-2】处理任务13

五、扩展

虚拟线程池

很新版本特性,了解即可。

相关推荐
先做个垃圾出来………2 小时前
Linux/Unix系统下的基础文本处理命令
java·linux·unix
风若飞2 小时前
Linux 环境下解决 Tomcat8 与 JDK8 配置问题
java·linux·运维·服务器·tomcat
ONExiaobaijs2 小时前
Java jdk运行库合集
java·开发语言·python
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-教学管理与用户管理模块联合回归测试文档
java·前端·数据库·人工智能·spring boot
Knight_AL2 小时前
一文讲透 Java 中transient的用处(结合 Flink 理解)
java·python·flink
xqqxqxxq2 小时前
《智能仿真无人机平台(多线程V1.0)技术笔记》(初识线程,带你理解程序运行的基本流程)
java·笔记
进阶小白猿2 小时前
Java技术八股学习Day23
java·网络·学习
砚边数影2 小时前
DL4J框架入门(三):基础配置,计算后端(CPU/GPU)选型与优化
java·数据库·人工智能·ai·金仓数据库
名字无法显示3412 小时前
Arthas 实战指南:结合 IDEA 的 Java 线上排查完整流程
java·intellij-idea