Java线程池的使用及工作原理
共 5752字,需浏览 12分钟
·
2021-06-06 15:06
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
前言
在日常开发过程中总是以单线程的思维去编码,没有考虑到在多线程状态下的运行状况。由此引发的结果就是请求过多,应用无法响应。为了解决请求过多的问题,又衍生出了线程池的概念。通过“池”的思想,从而合理的处理请求。本文记录了Java中线程池的使用及工作原理,如有错误,欢迎指正。
什么是线程池?
线程池要解决什么问题?
说到线程池就一定要从线程的生命周期讲起。
从图中可以了解无论任务执行多久,每个线程都要经历从生到死的状态。而使用线程池就是为了避免线程的重复创建,从而节省了线程的New
至Runnable
, Running
至Terminated
的时间;同时也会复用线程,最小化的节省系统资源,于此同时提高了响应速度。
线程池的使用
线程池的创建
使用ThreadPoolExecutor
并配置7个参数完成线程池的创建
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:线程池中核心线程的最大值
maximumPoolSize:线程池中最大线程数
keepAliveTime:非核心线程空闲的存活时间大小
unit:keepAliveTime的单位,常用的有秒、分钟、小时等
workQueue:阻塞队列类型
threadFactory:线程工厂,用于配置线程的名称,是否为守护线程等
handler:线程池的拒绝策略
常用阻塞队列
ArrayBlockingQueue
底层基于数组的实现的有界阻塞队列
LinkedBlockingQueue
底层基于单链表的阻塞队列,可配置容量,不配置容量默认为Integer.MAX_VALUE
线程工厂
在《阿里巴巴Java开发手册》中强制要求指定线程的名称
由于工作是使用hutool比较多,里面也包含对ThreadFactory
的封装,可以很方便的指定名称
ThreadFactory threadFactory = ThreadFactoryBuilder.create().setNamePrefix("myThread-").build();
拒绝策略
当线程池内工作线程数大于maximumPoolSize时,线程就不再接受任务,执行对应的拒绝策略;目前支持的拒绝策略有四种:
AbortPolicy(默认):丢弃任务并抛出
RejectedExecutionException
异常CallerRunsPolicy:由调用者处理
DiscardOldestPolicy:丢弃队列中最前面的任务,并重新入队列
DiscardPolicy:丢弃任务但不抛出异常
线程池的执行逻辑
// 创建线程工厂
ThreadFactory threadFactory = ThreadFactoryBuilder.create().setNamePrefix("myThread-").build();
// 创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), threadFactory, new ThreadPoolExecutor.AbortPolicy());
execute()方法
// 组合值;保存了线程池的工作状态和工作线程数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
public void execute(Runnable command) {
// 任务为空 抛出NPE
if (command == null)
throw new NullPointerException();
// 获取线程池状态
int c = ctl.get();
// 如果工作线程数小于核心线程数就创建新线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 如果线程池处于Running状态,就把任务放在队列尾部
if (isRunning(c) && workQueue.offer(command)) {
// 重新检查线程池状态
int recheck = ctl.get();
// 如果线程池不是Running状态,就移除刚才添加的任务,并执行拒绝策略
if (! isRunning(recheck) && remove(command))
reject(command);
// 是Running状态,就添加线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 添加任务失败,执行拒绝策略
else if (!addWorker(command, false))
reject(command);
}
// addWorker()完成线程的创建
执行流程
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:
https://blog.csdn.net/lhc_makefunny/article/details/117308066