这两天碰到关于线程池的一些概念,之前也是模模糊糊,现在总结一下。
1.何谓线程
- 线程是调度cpu的最小单元
- 线程分为用户级线程(ULT):App自己管理的线程;和内核级线程(KLT):操作系统管理的线程
- 在java中可以通过实现Runnable接口或者是继承Thread()类来创建线程,然后调用start()方法启动线程,(jvm中的线程模式属于内核级线程)
- 一个线程从创建到执行完成的整个生命周期分为五种状态,即创建、就绪、执行、阻塞、终止; 创建和终止的状态容易理解,就绪状态是当线程调用start() 方法后,进入就绪状态,此时线程处于就绪队列中,等待被调度; 运行状态:当线程获取到系统的资源后进入运行态; 阻塞状态:当正在运行的线程因特殊情况让出系统资源,进入阻塞状态,调度器立即调度就绪队列中的另一个线程运行,当阻塞事件解除后,该线程有阻塞状态回到就绪队列中等待被调度。
2.何谓线程池
顾名思义,线程池就是线程的池化管理,像一个大水池一样,里面有多个线程,可以对这个水池里面的所有线程统一管理,调度,监控;是一种多线程处理机制。
3.为什么要使用线程池
- 最大的原因,可以控制线程的并发数量,对所有的线程进行统一的管理和控制,从而提高系统的运行效率
- 线程和任务分离,提示线程的重用性;一个线程的创建和销毁是很消耗系统资源的操作,而使用线程池呢可以对一个线程重复使用,不用说这个线程的任务执行完后就立刻销毁,可以继续执行任务队列里面的任务,等所有任务全部执行完毕后再进行销毁;
- 上面我们说过,一个线程的生命周期内有五种状态,而使用线程池可以重复使用一个线程,假如创建一个线程用的时间为T1,执行任务的时间为T2,销毁线程的时间为T3,而使用线程池就省去了T1+T3的时间,提升系统的响应速度
4.使用线程池的部分代码、参数介绍
//构造方法
public ThreadPoolExecutor(int corePoolSize, //核心线程数量
int maximumPoolSize,// 最大线程数
long keepAliveTime, // 最大空闲时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 饱和处理机制
)
{ ... }
5.关于上面参数的介绍,我在网上找到了一个很容易理解的生活场景
我们可以通过下面的场景理解ThreadPoolExecutor中的各个参数;
a客户(任务)去银行(线程池)办理业务,但银行刚开始营业,窗口服务员还未就位(相当于线程池中初始线程数量为0),
于是经理(线程池管理者)就安排1号工作人员(创建1号线程执行任务)接待a客户(创建线程);
在a客户业务还没办完时,b客户(任务)又来了,于是经理(线程池管理者)就安排2号工作人员(创建2号线程执行任务)接待b客户(又创建了一个新的线程);假设该银行总共就2个窗口(核心线程数量是2);
紧接着在a,b客户都没有结束的情况下c客户来了,于是经理(线程池管理者)就安排c客户先坐到银行大厅的座位上(空位相当于是任务队列)等候,
并告知他: 如果1、2号工作人员空出,c就可以前去办理业务;
此时d客户又到了银行,(工作人员都在忙,大厅座位也满了)于是经理赶紧安排临时工(新创建的线程)在大堂站着,手持pad设备给d客户办理业务;
假如前面的业务都没有结束的时候e客户又来了,此时正式工作人员都上了,临时工也上了,座位也满了(临时工加正式员工的总数量就是最大线程数),
于是经理只能按《超出银行最大接待能力处理办法》(饱和处理机制)拒接接待e客户;
最后,进来办业务的人少了,大厅的临时工空闲时间也超过了1个小时(最大空闲时间),经理就会让这部分空闲的员工人下班.(销毁线程)
但是为了保证银行银行正常工作(有一个allowCoreThreadTimeout变量控制是否允许销毁核心线程,默认false),即使正式工闲着,也不得提前下班,所以1、2号工作人员继续待着(池内保持核心线程数量);
通过上面的生活场景可以说是很容易理解了,下面是线程池的工作流程示意图
6.关于一些常用的线程池使用可以参考下面的博文。
线程池参考:
[https://blog.csdn.net/hnd978142833/article/details/80253784]
7.线程池的使用步骤总结
- 利用Executors工厂类的静态方法,创建线程池对象;
- 编写Runnable或Callable实现类的实例对象;
- 利用ExecutorService的submit方法或ScheduledExecutorService的schedule方 法提交并执行线程任务
- 如果有执行结果,则处理异步执行结果(Future)
- 调用shutdown()方法,关闭线程池
对于线程池,由于现在的学习过程中有所涉及,先初略领会至此。