线程池
线程池
初始化线程池:
ThreadPoolExecutor executor = new ThreadPoolExecutor(10,10,10,TimeUnit.SECONDS, new LinkedBlockingQueue<>(10000),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
参数补充说明:
名称 | 类型 | 说明 |
---|---|---|
corePoolSize | int | 核心线程池大小 |
maximumPoolSize | int | 最大线程数大小 |
keepAliveTime | long | 线程最大空闲时间 |
unit | TimeUnit | 时间单位 |
workQueue | BlockingQueue |
线程等待队列 |
threadFactory | ThreadFactory | 线程创建工厂 |
handler | RejectedExecutionHandler | 拒绝策略,默认为AbortPolicy |
缓冲队列补充说明:
名称 | 说明 | 备注 |
---|---|---|
ArrayBlockingQueue | 构造必须指定大小 | 其所含的对象是FIFO顺序排序的 |
LinkedBlockingQueue | 大小不固定的BlockingQueue,其构造时指定大小,默认为Integer.MAX_VALUE | 其所含的对象是FIFO顺序排序的 |
PriorityBlockingQueue | 类似LinkedBlockingQueue | 排序是自然排序或按照对象的Comparetor排序 |
SynchronizedQueue | 特殊队列,存取必须是交替进行 |
ThreadPoolExecutor提供的拒绝策略补充说明:
名称 | 说明 | 备注 |
---|---|---|
AbortPolicy | 拒绝任务,直接抛出异常 | 默认策略 |
CallerRunsPolicy | 由主线程去执行任务 | |
DiscardPolicy | 丢弃任务,不抛出异常,也不执行 | 方法实现为空 |
DiscardOldestPolicy | 抛弃队列中最旧的任务,然后将任务加入队列中 |
Executors线程池工具类:
// 创建定长的线程池,必须根据实际情况估算出线程的数量
Executors.newFixedThreadPool(3);
// 创建一个可缓存的线程池,线程数量不做限制可根据需要灵活回收空闲线程,需要通过控制并发任务的数量来控制线程的数量
Executors.newCachedThreadPool();
// 创建一个定长的线程池,支持定时以及周期性执行的任务的需求
Executors.newScheduledThreadPool(5);
// 创建一个单线程的线程池,如果唯一的线程因异常而结束会创建一个新线程来替代它
Executors.newSingleThreadExecutor();
Executors.newSingleThreadScheduledExecutor();
// 创建一个具有抢占式操作的线程池
Executors.newWorkStealingPool();
Executor框架集
图
ExecutorService
juc.ExecutorService继承自Executor接口
ThreadPoolExecutor
成员变量:ctl:
// 表示两种含义:
// ①:workerCount:worker计数,表示正在处理中的任务
// ②:runState:运行状态,共5种见下表
// Integer值分32位,前3位是runState,后29位是workerCount
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
运行状态值
运行状态 | 十进制 | 二进制 | 说明 | 备注 |
---|---|---|---|---|
RUNNING | -1<<29 | 111000...000000 | 运行中 | 二进制为补码表示 |
SHUTDOWN | 0<<29 | 000000...000000 | 关闭,不再接受新任务,但仍然会处理排队任务 | 正数的原码,反码,补码均相同 |
STOP | 1<<29 | 001000...000000 | 停止,不接受新任务及排队任务,中断处理中的任务 | |
TIDYING | 2<<29 | 010000...000000 | 整理,所有任务终止,workerCount归0进入该状态 | 之后将调用terminal()钩子方法 |
TERMINATED | 3<<29 | 011000...000000 | 终止,terminal()已执行完成 |
更多细节还待学习...
问
核心线程数与最大线程数怎么配?
IO密集型任务:cpu核心数*2
为什么是这个数?
理想线程数 = ((CPU运算时间+IO等待时间) / CPU运算时间) * CPU核心数,CPU和IO时间相等时就是2倍CPU核心数
CPU密集型任务:cpu核心数+1,即:Runtime.getRuntime().availableProcessors()+1
为什么是cpu核心数+1?
《Java并发编程实战》一书中给出的原因是:即使当计算(CPU)密集型的线程偶尔由于页缺失故障或者其他原因而暂停时,这个“额外”的线程也能确保 CPU 的时钟周期不会被浪费。
线程池参数可通过相应的set方法动态修改,任务队列大小不支持动态修改,但可自定义阻塞队列来实现(容量大小不使用final修饰,提供set方法)
当修改最大线程数时如果新只小于当前值,则只会回收闲置线程
线程池被创建后里面有线程吗?如果有的话,有什么方法对线程池进行预热吗?
线程池被创建后如果没有任务过来,里面是不会有线程的。如果需要预热的话可以调用下面的两个方法:
// 启动全部核心线程,返回启动的数量
public int prestartAllCoreThreads()
// 启动一个核心线程,如果所有的
public boolean prestartCoreThread()
核心线程数会被回收吗?需要什么设置?
核心线程数默认是不会被回收的,如果需要回收核心线程数,需要调用下面的方法:
// allowCoreThreadTimeOut 该值默认为 false
public void allowCoreThreadTimeOut(boolean value)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!