一、线程池概述1.1、线程池概念在处理大量并发任务的时候如果按照传统的方式来一个任务请求创建一个线程来进行任务的处理大量线程的创建和销毁将消耗过多的系统资源还增加了线程上下文运行环境切换的开销而通过线程池技术就可以很好地解决这些问题。线程池技术通过在系统中预先创建一定数量的线程当任务请求到来时从线程池中分配一个预先创建的线程去处理任务线程在处理完任务之后并不会销毁,而是把线程归还到线程池中继续为后续的任务提供服务。图示:线程池的特点1.线程复用线程池会在内部维护一定数量的线程并在需要时重复使用这些线程来执行任务避免频繁地创建和销毁线程从而提高性能和效率。2.控制并发性对于多核处理器由于多线程被分配到多个处理器中,提高并行处理的效率。线程池可以控制并发执行的线程数量通过设定线程池的大小来限制系统中同时执行的线程数量避免资源的过度占用和线程竞争导致的性能下降。3.任务排队当线程池中的线程已经全部被占用时新提交的任务会被放入一个任务队列中进行排队等待执行。排队机制可以根据具体线程池的实现选择不同的队列类型如有界队列或无界队列。4.提高任务的响应速度当任务到达时不需要等待线程创建就能立即执行任务5.提供线程管理和监控线程池提供了易于管理和监控线程的方式可以设置线程的属性、监控线程的状态、统计任务执行情况等。6.避免资源的过度消耗线程池可以通过限制线程数量和排队机制来避免过度消耗系统资源。当系统负载过高时线程池可以根据配置策略进行线程数量的自动调整以保持系统的稳定性和性能。7.提供任务执行的灵活性线程池可以接受不同类型的任务并对这些任务进行执行调度。它提供了一系列提交任务的方法如execute()、submit()同时还支持定时执行和周期性执行任务的能力。涉及知识点1.熟悉多线程理论多线程基本知识,线程同步,线程互斥,原子操作等2.熟悉C11并发支持库如thread,mutex,condition_variable,atomic,unique_lock等3.熟悉C11的完美转发lambda表达式4.熟悉C11智能指针的使用5.熟悉CSTL容器库的使用开发环境:window : vs2019Liunx :g要求g版本能够支持C11以上1.2、按应用场景分类1.FixedThreadPool固定线程池线程池中的线程数量固定这些线程会一直存在不会随任务的增加或减少而动态调整超出的任务会在队列中等待。使用场景任务量比较固定但耗时较长的任务。2.CachedThreadPool缓存线程池可根据需要创建新线程的线程池如果新任务到达但线程池中没有可用线程则创建一个新线程并添加到池中如果有被使用完但是还没销毁的线程就复用该线程。线程池中超过60秒未使用的线程将会被移除和销毁。使用场景任务量大但耗时少的任务3.SingleThreadPool单线程池使用唯一的工作线程来执行任务保证所有任务按照指定顺序(FIFO, LIFO,优先级)执行。使用场景多个任务顺序执行(FIFO,优先级)。4.WorkStealingPool工作窃取线程池创建一个拥有多个任务队列以便减少连接数的线程池使用场景会创建一个含有足够多线程的线程池来维持相应的并行级别它会通过工作窃取的方式使得多核的CPU不会闲置总会有活着的线程让CPU去运行。如果当前工作线程处理完自己本地任务队列中的任务时就会去全局队列或者其他工程线程的队列里面查找工作任务帮助它们完成。利用Work Staling可以更好实现负载均衡。5.ScheduledThreadPool计划线程池定时线程池调度线程池使用场景定时以及周期性执行任务。1.3、线程池模式线程池模式一般分为两种L/F领导者与跟随者模式, HS/HA半同步/半异步模式。领导者跟随者模式在线程池中的线程可处在3种状态之一领导者leader、追随者follower或工作者processor。任何时刻线程池只有一个领导者线程。事件到达时领导者线程负责消息分离并从处于追随者线程中选出一个来当继任领导者然后将自身设置为工作者状态去处置该事件处理完毕后工作者线程将自身的状态置为追随者。在ACE中提供了领导者跟随者模式实现。半同步/半异步模式又称为生产者消费者模式是比较常见的实现方式比较简单。分为同步层、队列层、异步层三层。同步层的主线程处理工作任务并存入工作队列工作线程从工作队列取出任务进行处理如果工作队列为空则取不到任务的工作线程进入挂起状态。由于线程间有数据通信因此不适于大数据量交换的场合。1.4、半同步/半异步模式分析图示:1.同步服务层它处理来自上层的任务请求上层的请求可能是并发的这些请求不是马上就会被处理而是将这些任务放到一个同步排队层中等待处理。2.同步排队层来自上层的任务请求都会加到排队层中等待处理。3.异步服务层这一层中会有多个线程同时处理排队层中的任务异步服务层从同步排队层中取出任务并行的处理。这种三层的结构可以最大程度处理上层的并发请求。对于上层来说只要将任务丢到同步队列中就行了至于谁去处理什么时候处理都不用关心主线程也不会阻塞还能继续发起新的请求。至于任务具体怎么处理这些细节都是靠异步服务层的多线程异步并行来完成这些线程是一开始就创建的不会因为大量的任务到来而创建新的线程避免了频繁创建和销毁线程导致的系统开销而且通过多核处理能大幅提高处理效率。1.5、线程池实现的关键技术分析线程池的基本概念和基本结构它是由三层组成同步服务层、排队层和异步服务层其中排队层居于核心地位因为上层会将任务加到排队层中异步服务层同时也会取出任务这里有一个同步的过程。在实现时排队层就是一个同步队列允许多个线程同时去添加或取出任务并且要保证操作过程是安全的。线程池有两个活动过程一个是往同步队列中添加任务的过程另一个是从同步队列中取任务的过程。半同步半异步线程池活动图从活动图中可以看到线程池的活动过程一开始线程池会启动一定数量的线程这些线程属于异步层主要用来并行处理排队层中的任务如果排队层中的任务数为空则这些线程等待任务的到来如果发现排队层中有任务了线程池则会从等待的这些线程中唤醒一个来处理新任务。同步服务层则会不断地将新的任务添加到同步排队中这里有个问题值得注意有可能上层的任务非常多而任务又是非常耗时的这时异步层中的线程处理不过来则同步排队层中的任务会不断增加如果同步排队层不加上限控制则可能会导致排队层中的任务过多内存暴涨的问题。因此排队层需要加上限的控制当排队层中的任务数达到上限时就不让上层的任务添加进来起到限制和保护的作用。关键补充IO密集型与计算密集型任务理解线程池的核心后我们必须掌握“任务类型”——因为不同类型的任务对线程池的参数配置核心线程数、最大线程数、队列大小影响极大。最常见的任务类型分为两种IO密集型和计算密集型。一计算密集型任务所谓计算密集型任务核心是“大量的CPU运算”任务的执行时间主要消耗在CPU的计算上几乎不涉及外部资源的等待如磁盘IO、网络请求、数据库操作等。举个例子矩阵乘法、质数计算、数据排序、复杂算法运算等这些任务会持续占用CPU直到计算完成。核心特点CPU利用率极高几乎100%任务执行期间线程不会空闲一直占用CPU资源。线程池适配建议计算密集型任务的线程数不宜过多否则会导致大量线程竞争CPU频繁进行上下文切换反而降低效率。最优线程数配置线程数 ≈ CPU核心数 11是为了应对偶尔的线程阻塞避免CPU空闲。比如我们的电脑是4核CPU计算密集型任务的线程池核心线程数设置为5左右最合适。适配的线程池类型固定线程池FixedThreadPool因为固定线程数能稳定控制并发度避免线程过多导致的CPU过载。二IO密集型任务IO密集型任务核心是“等待外部资源”任务的执行时间主要消耗在等待上如等待磁盘读写、等待网络响应、等待数据库返回结果CPU的利用率极低大部分时间线程处于空闲等待状态。举个例子文件读写、HTTP请求、数据库查询、网络爬虫等这些任务中线程大部分时间都在等待外部资源就绪CPU几乎处于空闲状态。核心特点CPU利用率低线程空闲时间长适合多线程并行执行通过多线程弥补等待时间的浪费。线程池适配建议IO密集型任务的线程数可以适当多一些因为线程大部分时间在等待多线程可以让CPU在等待期间处理其他任务提高整体效率。最优线程数配置线程数 ≈ 2 × CPU核心数也可以根据实际等待时间调整等待时间越长线程数可以越多。比如4核CPUIO密集型任务的线程池核心线程数可以设置为8-10。适配的线程池类型缓存线程池CachedThreadPool因为缓存线程池可以动态伸缩线程数当有大量IO任务时自动创建更多线程当任务减少线程空闲超时后自动销毁避免资源浪费。一、线程池与任务类型的核心关联总结很多人使用线程池时只知道“创建线程池、提交任务”却忽略了任务类型导致线程池配置不合理性能达不到预期。其实核心逻辑很简单线程池的线程数本质是“平衡CPU利用率和任务等待时间”——计算密集型怕CPU过载所以线程数少IO密集型怕CPU空闲所以线程数多。结合我们之前实现的6种线程池补充适配场景计算密集型固定线程池、工作窃取线程池多核场景下负载均衡效率更高IO密集型缓存线程池、定时调度线程池如定时网络请求需要任务顺序/优先级单线程池、优先级线程池。二、学习小结通过本文的学习我们不仅深化了对线程池的理解——线程池的核心是“线程复用并发度控制”解决了线程频繁创建销毁的性能问题更掌握了线程池使用的关键根据任务类型IO密集型/计算密集型配置合理的线程数和线程池类型。后续学习中我们可以结合实际场景尝试调整线程池的参数核心线程数、最大线程数、空闲超时时间等观察任务执行效率的变化进一步理解线程池的底层逻辑。同时也可以尝试完善线程池的功能如添加任务拒绝策略、线程池监控等让线程池更贴合实际开发需求。