例子:银行有五个窗口,平时开三个窗口服务,客流量大时进行自适应服务,等候区有三个座位,也就是说一次银行里最多有八个顾客(别杠,只是例子),用Java语言模拟场景。
线程池利用池化思想,像字符串常量池、数据库连接池
目的:
①降低资源的消耗,通过重复利用已经创建的线程降低线程创建和销毁造成的消耗。
②提高相应速度,当任务到达的时候,任务可以不需要等到线程创建就能立刻执行。
③提高线程的可管理性,线程是稀缺资源,使用线程池可以统一的分配、调优和监控。
线程池原理:
1)如果workerCount < corePoolSize ==> 创建线程执行提交的任务
2)如果workerCount >= corePoolSize && 阻塞队列未满 ==> 添加至阻塞队列,等待后续线程来执行提交地任务
3)如果workerCount >= corePoolSize && workerCount < maxinumPoolSize && 阻塞队列已满 ==> 创建非核心线程执行提交的任务
4)如果workerCount >= maxinumPoolSize && 阻塞队列已满 ==> 执行拒绝策略
线程池参数:
corePoolSize:核心线程数,线程池中频繁使用的线程,像例子中的常开的三个服务窗口。
maximumPoolSize:最大线程数,线程池可容纳的线程数,像例子中的五个服务窗口。
keepAliveTime:空闲线程存活时间,当一个可被回收的线程的空闲时间大于keepAliveTime,就会被回收,就像服务窗口客流量少,就会自适应关闭个别窗口。
unit:时间单位,KeepAliveTime的存活时间,例如规定多余银行窗口4个小时没人来办理业务就关闭
workQueue:工作队列,例如银行的等候区,服务窗口满了就在等待区等待
threadFactory:线程工厂,项目开发额过程中,如果有很多地方使用多线程,那么给线程命名是十分有必要的,这样当出现问题的时候就比较容易排查
handler:拒绝策略,当线程池线程数已满,并且工作队列达到限制,新提交的任务使用拒绝策略处理。例如银行服务窗口和等候区都满了,那只能去下一个网点办理业务。
【实现代码】
/**
* ZAY 2023.9.13
**/
import java.util.concurrent.*;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(3, 5, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 6; i++){
executorService.execute(()->{
System.out.println(Thread.currentThread().getName() + "===>办理业务");
});
}
executorService.shutdown();
}
}