一、线程池的优点
说到线程池的优点就要先说一下不用线程池的坏处
- 在早些年开发都是直接new Thread()直接创建线程,倘若有N个异步就要创建N个线程,这会导致线程的频繁创建和销毁
- 线程不可控,每个线程都各自执行,内存资源竞争激烈,这可能会导致OOM
使用线程池的好处
- 不用频繁创建线程,可重用线程池中的线程,免去了频繁创建的性能开销
- 可控制线程的最大并发,超过一定数量的线程进入队列等待执行
二、线程池的使用
1.线程池的参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize 核心线程数: 默认情况下线程在空闲状态下不会被销毁,而是一直处于存活状态。可以通过allowCoreThreadTimeOut(boolean value)设置核心线程超时被回收,也就是说当核心线程空闲时间超过keepAliveTime的时候,就被回收了
maximumPoolSize 最大线程数: 线程池中最大的并发执行线程数量,因此也引出了非核心线程数(非核心线程数=最大线程数-核心线程数)
keepAliveTime 线程空闲状态下存活的时间长度: 设置存活时间
TimeUnit 时间单位: 可设置毫秒 秒等等
BlockingQueue 线程队列: 当线程数超过核心线程数,线程就会放到队列等待执行
ThreadFactory 线程工厂: 为线程池提供创建新的线程的功能
RejectedExecutionHandler 拒绝策略: 当线程池需要执行的数量超过一定容量(核心线程数+线程队列最大长度+非核心线程数)时会抛出RejectedExecutionException异常
三、执行策略
我们用currentSize表示当前需要执行的线程数,用coreSize表示核心线程数
- 当currentSize<=coreSize时,会直接用核心线程来执行
- 当currentSize>coreSize时,先用完全部的核心线程去执行,然后剩下的线程加入的线程队列等待执行
- 此时如果线程队列已经满了的话,就会创建非核心线程去执行,但是正常执行的前提是currentSize<=coreSize+线程队列最大容量+非核心线程数(非核心线程数=最大线程数-核心线程数),否则的话就会触发拒绝策略,抛出RejectedExecutionException异常。
小结:优先使用核心线程,核心线程用完了就往线程队列里塞,线程队列塞满了再去启动非核心线程,一旦超过了最大线程数,就会抛异常。
四、其他创建线程池的方法
通过Executors直接创建线程池,相对于直接new ThreadPoolExecutor来说,不需要自己设置很多参数,查看源码就能发现其实Executors也是对ThreadPoolExecutor操作的,在现实开发中可以根据业务需求创建不同的线程池。