Java线程池原理
·
1,写在前面:
线程池是一种池化技术,核心思想就是复用线程,避免每次来一个任务就new一个Thread,因为创建线程和销毁线程的开销都不小,一个线程起码占用1MB左右的栈空间,还有操作系统层面的调度成本。
线程池有几个关键参数:核心线程数、最大线程数、空闲存活时间、工作队列、拒绝策略。

2,工作流程
- 任务来了先看核心线程够不够用,不够就创建新线程处理。默认核心线程是懒创建的,有任务才new,不过可以通过prestartAllCoreThreads预热。
- 核心线程数满了之后,新任务不会立刻创建线程,而是先丢到工作队列里面排队。
- 队列里面也塞满了,这时候才会创建非核心线程,最多创建到最大线程数。
- 队列满了,线程也到顶了,再来任务就触发拒绝策略。
- 线程空闲时间超过keepAliveTime,并且当前线程数超过核心线程数,多余的线程会被回收。设置allowCoreThreadTimeOut为true的话连核心线程也能回收。
3,图解线程池执行流程
- 任务提交,线程池线程数还未达到核心线程数:

- 核心线程数已满,任务队列未满的情况:

- 核心线程数已满,任务队列也满了的情况:

- 线程池中线程数已达最大线程数的情况:

注意:核心线程和非核心线程在线程池内部压根没有标识区分,都是普通的Worker对象。图中区分只是为了说清楚创建顺序。
4,为什么是先排队而不是先加线程?
很多人一开始可能都会觉得很奇怪,任务多了为啥不直接加线程干活,非要先排队?
原因是线程不是免费的。每次创建一个线程起码占用1MB的栈空间,操作系统还要维护线程上下文、调度开销。如果任务突然来一波就疯狂创建线程,系统资源很快耗尽,CPU光切换上下文就忙不过来了。
队列的作用是削峰填谷。任务暂时堆在队列里,让现有线程慢慢消化。如果队列塞满了说明真扛不住了,这时候才加线程救急。
举个例子:餐厅有5个服务员正常情况下就够用,如果突然一下子来了30个客人,老板不会立马招25个临时工,而是让客人先排队等位。如果排队都排到门外了,才考虑加人。
5,核心参数的实际含义
ThreadPoolExecutor的7个核心参数:
- corePoolSize:核心线程数,线程池平时维护的线程数量。即使这些线程空闲也不会被回收,除非设置了allowCoreThreadTimeOut。
- maximumPoolSize:最大线程数,线程池能创建的线程上限。核心线程满了、队列满了才会创建到这个数。
- keepAliveTime和unit:空闲线程的存活时间。超过核心线程数的那部分线程,空闲超过这个时间就会被回收。
- workQueue:任务队列,核心线程忙不过来时任务就在这排队。
- threadFactory:线程工厂,用来创建线程。可以自定义线程名方便排查问题。比如给线程起名叫order-pool-thread-1。
- handler:拒绝策略,队列满了,线程也到顶了,新任务怎么处理。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)