JAVA理论第四战-线程池
4.1 为什么需要线程池
在实际使用中,线程时很占用系统资源的,如果对线程管理不完善的话很容易导致系统问题。因此对线程管理不完善的话很容易导致系统问题。因此,在大多数并发框架中都会使用 线程池来管理线程,使用线程池管理线程主要有如下好处:
- 使用线程池可以重复利用已有的线程执行任务,避免线程在创建时造成消耗
- 由于没有线程创建和销毁时的消耗,可以提高系统响应速度
- 通过线程可以对线程进行合理的管理,根据系统的承受能力调整可运行线程数量的大小等
4.1.1线程池的主要核心原理
- 创建一个池子,池子中是空的
- 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子。下次再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
- 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
4.2线程池的分类

- newCachedThreadPool:创建一个可进行缓存重复利用的线程池
- newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,线程池中的线程处于一定的量,可以很好的控制线程的并发量
- newSingleThreadExecutor:创建一个使用单例worker线程的Executor,以无界队列方式来运行该线程。线程池中最多执行一个线程,之后提交的线程将会排在队列中以此执行
- newSingleThreadScheduledExecutor:创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期执行
- newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期的执行
- newWorkStealingPool:创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,如不传并行级别参数,将默认为当前系统的CPU个数
4.3 核心参数
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor
- corePoolSize(正式员工数量):核心线程池的数量(大于0)
- maximumPoolSize(餐厅最大员工数):线程池能创建线程的最大数量(大于核心线程数)
- keepAliveTime(临时员工空闲多长时间被辞退):空闲线程存活时间
- unit(空闲时间的时间单位例如Hours):时间单位,为keepAliveTime指定时间单位
- workQueue(排队的客户):阻塞队列,用于保存任务的阻塞队列
- threadFactory(从哪里招人):创建线程的工程类
- handler(当排队人数过多,超出顾客请下次再来(拒绝服务):饱和策略(拒绝策略)
4.4 线程池的原理

当一个任务提交至线程池之后
- 线程池首先会判断核心线程池里的线程是否满了。
- 如果没满,则创建一个新的工作线程
- 如果核心线程池满了,再去判断阻塞队列是否已经满了。
- 如果没有满,将任务存储的工作队列中
- 如果阻塞队列满了,再去判断线程池都满了,
- 如果没有满,则创建一个新的工作线程来执行,
- 如果满了按照饱和策略进行处理
4.5 拒绝策略
ThreadPoolExecutor.AbortPolicy(系统默认): 丢弃任务并抛出RejectedExecutionException异常,让你感知到任务被拒绝了,我们可以根据业务逻辑选择重试或者放弃提交等策略
ThreadPoolExecutor.DiscardPolicy:也就是 丢弃任务,但是不抛出异常,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失
ThreadPoolExecutor.DiscardOldestPolicy: 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程),通常是 存活时间最长的任务,它也存在一定的数据丢失风险
ThreadPoolExecutor.CallerRunsPolicy:: 既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,让调用者去执行它。
4.6 线程池的关闭
关闭线程池,可以通过 shutdown和 shutdownNow两个方法
原理:遍历线程池中的所有线程,然后依次中断
- shutdownNow:首先将线程池的状态设置为STOP,然后尝试停止所有的正在执行和未执行任务的线程,并放回等待执行任务的列表
- shutdown:只是将线程池的状态设置为SHUTDOWN状态,然后中断所有没有正在执行任务的线程