JUC-线程池

184 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

线程池

1.什么是线程池

线程池是一种多线程处理形式,处理过程中将任务提交到线程池,任务的执行交由线程池来管理。

因为创建线程和销毁线程的花销是比较大的,这些时间有可能比处理业务的时间还要长。这样频繁的创建线程和销毁线程,再加上业务工作线程,消耗系统资源的时间,可能导致系统资源不足。

使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以被重复利用,执行多个任务。提高程序效率的同时还方便管理以及限流。

2.线程池的参数

corePoolSize:线程池中的核心线程数量,即使在没有用的时候,也不会被回收(设置了 allowCoreThreadTimeOut 除外);

maximumPoolSize:线程池中可以容纳的最大线程的数量;

keepAliveTime:线程池中除了核心线程之外的其它线程的最长可以保留的时间;

util:空闲线程存活时间单位,即 keepAliveTime 的时间单位;

workQueue:工作队列,任务可以储存在任务队列中等待被执行,执行的是 FIFO 原则(先进先出);

threadFactory:创建线程的线程工厂类,可以用来设定线程名、是否为 daemon 线程等;

handler:拒绝策略,可以在任务满了之后采用一定策略拒绝执行某些任务。

3.线程增长的过程

主要是理解 corePoolSize、maximumPoolSize 和 workQueue 之间的关系。

1)当线程池中线程数量小于 corePoolSize 核心线程数时,新提交的任务就会创建一个新线程执行,即使线程池中存在空闲线程;

2)当线程池中线程数量达到 corePoolSize 核心线程数后,新提交的任务就会被放到 workQueue 工作队列中,等待被线程池调度执行;

3)当 workQueue 也满了后,且满足当前线程数量是否小于 maximumPoolSize 最大线程数量时,新提交任务将继续创建新的线程执行;

4)若线程数量达到 maximumPoolSize 最大线程数量,则新提交任务交予 handler 拒绝策略处理。

4.线程池的拒绝策略

在线程池 ThreadPoolExecutor 中,已经包含四种处理策略。

AbortPolicy:直接丢弃任务,并抛出 RejectedExecutionException 异常,也是线程池默认采用的策略;

CallerRunsPolicy:在调用者线程中直接执行被拒绝任务的 run 方法,除非线程池已经 shutdown,则直接抛弃任务;

DiscardOleddestPolicy:抛弃进入队列最早的那个任务,也是即将被执行的任务,然后尝试把这次拒绝的任务放入队列;

DiscardPolicy:直接丢弃任务,不予任何处理。

除了 JDK 默认提供的四种拒绝策略,我们可以通过实现 RejectedExecutionHandler 接口根据自己的业务需求去自定义拒绝策略。

5.线程池的工作队列

ThreadPoolExecutor 线程池的工作队列可以分为两大类:无界队列和有界队列。

ArrayBlockingQueue 是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

LinkedBlockingQueue 一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。newFixedThreadPool 使用了这个队列。

容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE。

SynchronousQueue 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue。newCachedThreadPool 线程池使用了该队列。

PriorityBlockingQueue 一个具有优先级的无限阻塞队列。

DelayQueue 是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool 线程池使用了这个队列。

无界队列不存在饱和的问题,但是其问题是当请求持续高负载的话,任务会无脑的加入工作队列,那么很可能导致内存等资源溢出或者耗尽。而有界队列不会带来高负载导致的内存耗尽的问题,但是有引发工作队列已满情况下,新提交的任务如何管理的难题,这就是线程池工作队列饱和策略要解决的问题。

6.线程池的常用场景?

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newWorkStealingPool 一个拥有多个任务队列的线程池,可以减少连接数,创建当前可用 cpu 数量的线程来并行执行。