线程池全面总结 (3)

待处理工作job的存储队列:工作者线程workers的数量是有限的,同一时间最多只能处理最多workers数量个job。对于来不及处理的job需要保存到等待队列里,空闲的工作者work会不停的读取空闲队列里的job进行处理。基于不同的队列实现,可以扩展出多种功能的线程池,如定制队列出队顺序实现带处理优先级的线程池、定制队列为阻塞有界队列实现可阻塞能力的线程池等。流控一方面通过控制worker数控制并发数和处理能力,一方面可基于队列控制线程池处理能力的上限。

线程池初始化:即线程池参数的设定和多个工作者workers的初始化。通常有一开始就初始化指定数量的workers或者有请求时逐步初始化工作者两种方式。前者线程池启动初期响应会比较快但造成了空载时的少量性能浪费,后者是基于请求量灵活扩容但牺牲了线程池启动初期性能达不到最优。

处理业务job算法:业务给线程池添加任务job时线程池的处理算法。有的线程池基于算法识别直接处理job还是增加工作者数处理job或者放入待处理队列,也有的线程池会直接将job放入待处理队列,等待工作者worker去取出执行。

workers的增减算法:业务线程数不是持久不变的,有高低峰期。线程池要有自己的算法根据业务请求频率高低调节自身工作者workers的 数量来调节线程池大小,从而实现业务高峰期增加工作者数量提高响应速度,而业务低峰期减少工作者数来节省服务器资源。增加算法通常基于几个维度进行:待处 理工作job数、线程池定义的最大最小工作者数、工作者闲置时间。

线程池终止逻辑:应用停止时线程池要有自身的停止逻辑,保证所有job都得到执行或者抛弃。

 

 

线程池的优点:

1.重用线程池中的线程,减少因对象创建,销毁所带来的性能开销;

2.能有效的控制线程的最大并发数,提高系统资源利用率,同时避免过多的资源竞争,避免堵塞;

3.能够多线程进行简单的管理,使线程的使用简单、高效。

4.减少频繁的创建和销毁线程(由于线程创建和销毁都会耗用一定的内存)

5.线程池也是多线程,充分利用CPU,提高系统的效率

6.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用。

7.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。

8.线程复用

9.控制最大并发数

10.管理线程

 

线程池的工作过程如下:

 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

 当调用 execute() 方法添加一个任务时,线程池会做如下判断:

 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;

 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;

 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常RejectExecutionException。

 当一个线程完成任务时,它会从队列中取下一个任务来执行。

 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

 

执行流程

 调用ThreadPoolExecutor的execute提交线程,首先检查CorePool,如果CorePool内的线程小于CorePoolSize,新创建线程执行任务。

 如果当前CorePool内的线程大于等于CorePoolSize,那么将线程加入到BlockingQueue。

 如果不能加入BlockingQueue,在小于MaxPoolSize的情况下创建线程执行任务。

 如果线程数大于等于MaxPoolSize,那么执行拒绝策略。

 

配置线程池的大小

一般需要根据任务的类型来配置线程池大小:

 如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1;

 如果是IO密集型任务,参考值可以设置为2*NCPU。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydswf.html