线程池执行原理与自定义线程池
线程池执行原理:
日常记录
(一)丶使用线程池的优点:
池化技术应用:线程池、数据库连接池、http连接池等等。
池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。
线程池提供了一种限制、管理资源的策略。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。
(二)丶使用线程池的好处:
降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。
提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,监控和调优。
ThreadPoolExecutor:上层关系
执行流程:
线程池执行图:
线程池执行顺序:
线程池中线程,由executos()方法执行,创建线程,当线程池中常驻线程数量,无法处理,过多时,多于的请求,会被存放到堵塞队列中
,当堵塞队列中,存放请求已满时,会在线程池中,重新创建新线程,并且将堵塞队列,无法存放的过多请求,交由新创的线程处理
,再如果,请求数量,大于线程池中,最大线程处理数量时,那么线程将会执行拒绝策略(四种)
- AbortPolicy:拒绝,过多请求任务策略,并且抛出异常:RejectedExecutionException
- CallerRunsPolicy:将请求任务退回给,调用者
- DiscardOldestPolicy:抛弃队列中,等待最长的请求任务,然后把当前任务,加入队列中,排队处理
- DiscardPolicy:丢弃无法,处理的请求任务,不做任何处理
自定义线程池:
不使用JDK的Executors创建线程池原因:
1.FixedThreadPool和SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM(内存溢出)
2.CachedThreadPool和ScheduledThreadPool:
允许创建线程数量为:Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM
详细:参考阿里开发手册
线程池配置(重要)
CPU密集型任务配置:即任务需要大量运算,没有大阻塞,CPU必须保证近乎全开状况
线程池最大线程配置:在CPU全开情况下,CPU核数 + 一个线程的线程池
比如八核CPU:
线程池配置:
corePoolSize:1
maximumPoolSize:8 + 1
比如8核CPU: 8 + 1 = 9个线程(最大池中线程数量)
比如:运行长时间超复杂算法的程序
IO密集型任务配置:即任务需要大量IO,即最大阻塞(但是并非一直执行任务,只是某个时刻或者时段)
IO密集型时,大部分线程都阻塞,故需要多配置线程数:
配置方式一:
线程池:CPU * 2 (比如 *2,做为参考)
比如8核CPU: 8 * 2 = 16个线程(最大池中线程数量)
配置方式二:
参考公式:CPU核数 / 1 - 阻塞系数 阻塞系数:0.8 ~ 0.9 之前取值
比如8核CPU: 8 / 1 - 0.9 = 80个线程
比如:在某个时刻对数据读取的大量操作
建议具体问题具体分析
自定义线程池示范:
import java.util.concurrent.*;
/**
* 自定义线程池:
* 创建线程池对象:
* 线程池基本,7个参数:
* 1.常驻线程数量 - corePoolSize
* 2.最大线程数量 - maximumPoolSize
* 3.线程消亡时间 - keepAliveTime
* 4.线程消亡时间单位 - deadTime (TimeUnit.)
* 5.堵塞队列 - BlockingQueue<Runnable>
* 6.拒接策略 - RejectedExecutionHandler(四种策略)
* 7.线程工厂 - ThreadFactory
*
* 线程池执行流程:
* 线程池中线程由,executos()方法执行,创建线程,当线程池中常驻线程数量,无法处理,请求时,多于的请求,会被存放到堵塞队列中
* ,当堵塞队列中,请求已满时,会在线程池中,重新创建线程,并且将队列,无法存放的过多请求,交由新创的线程处理
* ,再如果,请求数量大于,线程池中最大线程处理数量时,那么线程将会执行拒绝策略(四种)
* 拒绝策略:
* AbortPolicy:拒绝,过多请求任务策略,并且抛出异常:RejectedExecutionException
* CallerRunsPolicy:将请求任务退回给,调用者
* DiscardOldestPolicy:抛弃队列中,等待最长的请求任务,然后把当前任务,加入队列中,排队处理
* DiscardPolicy:丢弃无法,处理的请求任务,不做任何处理
*
* 不使用JDK的Executors创建线程池原因:
* 1.FixedThreadPool和SingleThreadPool:
* 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM(内存溢出)
* 2.CachedThreadPool和ScheduledThreadPool:
* 允许创建线程数量为:Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM
*/
public class CustomThreadPool {
private static volatile int corePoolSize=2;//常驻线程池数量
private static volatile int maximumPoolSize=5;//最大线程池数量
private static volatile Long keepAliveTime=1L;//消亡时间
private static volatile TimeUnit deadTime=TimeUnit.SECONDS;//时间单位
private static final ArrayBlockingQueue<Runnable> arrayBlockingQueue=new ArrayBlockingQueue<>(4);//存放请求任务数量
private static final RejectedExecutionHandler rejectedExecutionHandler=new ThreadPoolExecutor.AbortPolicy();//拒绝策略
private static volatile ThreadFactory threadFactory = Executors.defaultThreadFactory();//创建默认线程工厂
public static void main(String[] args) {
//创建线程池对象
ExecutorService executorService = new ThreadPoolExecutor(corePoolSize
,maximumPoolSize
,keepAliveTime
,deadTime
,arrayBlockingQueue
,threadFactory
,rejectedExecutionHandler);
try {
for (int i = 1; i <=100 ; i++) {
executorService.execute(()->{
System.out.println("当前线程:"+Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//一定要释放线程
executorService.shutdown();
}
}
}