线程池是什么?
线程池的工作机制是什么?
线程池带来了哪些好处?
通过名称可以知道,线程池实际是管理线程的地方,当我们要持续的创建线程,销毁线程的时候,线程池是一个不错的解决方案,java本身也自带了线程池的实现.
线程池的基本原理
当把任务提交给线程池的的时候,其工作流程:
- 线程池判断核心线程池里的线程是否有空闲的,如果有,创建一个新线程执行任务,反之,走下面流程
- 判断工作队列是否已满.如果没有,提交新的任务在这里队列里,反之,执行下面步骤
- 线程池判断线程池的线程是否都处于工作状态,如果没有,创建一个新的工作线程来执行任务,反之,交给饱和策略处理任务
其流程图大概是:
ThreadPoolExecutor
用以下代码创建一个线程池:
public class CreateThreadPool {
private static int poolSize = 5;
private static int maximumPoolSize = 7;
private static int keepAliveTime = 7000;
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(poolSize,maximumPoolSize,keepAliveTime,
TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>());
}
}
构造方法的全部参数分别为:
- poolSize 核心线程池的大小
- maximumPoolSize 线程池最大线程数
- keepAliveTime 线程池没有任务时,所持续的最大时间
- TimeUnit 上面参数的单位
- workQueue 线程池用的核心队列
- threadFactory 线程工厂,主要创建线程,默认是Executors.defaultThreadFactory()
- handler 线程池饱和策略的处理器,默认是ThreadPoolExecutor.AbortPolicy这个内部抽象类(抛出异常).
其中,饱和策略,也就是handler参数,jsk中给了四个默认的办法:
- AbortPolicy 直接抛出异常
- CallerRunsPolicy 只用调用者的线程来执行任务
- DiscardOldestPolicy 舍弃最后的任务,执行当前任务
- DiscardPolicy 不做处理
至于workQueue队列,可以有一下几个:
- ArrayBlockingQueue 基于数组的有界阻塞队列,FIFO
- LinkedBlockingQueue 基于链表的阻塞队列,FIFO
- SynchronousQueue 不做存储的队列,进入队列前,必须等到另一个线程调用移除操作.
- PriortityBlockingQueue 有优先级的无解阻塞队列
配置线程池的原则
主要考虑一下几点:
- 任务的性质: CPU密集,IO密集,和混合型
- 任务的优先级: 高,中,低
- 任务的执行时间: 短,中,长
- 任务的依赖性: 是否依赖修通资源,如数据库等等
任务的不同,可以相应的选择不同的线程池.CPU密集的,可以配置尽可能少的线程,比如CPU核数+1
IO密集型可以2*cpu合数.
如果线程有优先级,那么可以考虑上面的PriortityBlockingQueue 用作线程池的队列.