Java并发编程:线程池的使用
线程池基础
- 请求队列 线程池维护一定数量的线程,当线程池在运行状态的线程数量达上限时,其他线程被放入各请求队列,排除等待线程池释放提供资源。
1. 线程池状态
volatile int runState; //运行状态
//当创建线程池后,初始时,线程池处于RUNNING状态
static final int RUNNING = 0;
//调用了shutdown()方法;此时等待池内和队列中所有线程执行完毕,不接受新任务
static final int SHUTDOWN = 1;
//调用了shutdownNow()方法; 此时尝试终止正在执行的任务,且拒绝接受新任务
static final int STOP = 2;
//shutdown或stop 且所有工作线程销毁,队列清空。
static final int TERMINATED = 3;
2. 任务的执行
private final BlockingQueue<Runnable> workQueue; //任务缓存队列,用来存放等待执行的任务
private final ReentrantLock mainLock = new ReentrantLock(); //线程池的主要状态锁,对线程池状态(比如线程池大小、runState等)的改变都要使用这个锁
private final HashSet<Worker> workers = new HashSet<Worker>(); //用来存放工作集
private volatile long keepAliveTime; //线程存活时间
private volatile boolean allowCoreThreadTimeOut; //是否允许为核心线程设置存活时间
private volatile int corePoolSize; //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)
private volatile int maximumPoolSize; //线程池最大能容忍的线程数
private volatile int poolSize; //线程池中当前的线程数
private volatile RejectedExecutionHandler handler; //任务拒绝策略
private volatile ThreadFactory threadFactory; //线程工厂,用来创建线程
private int largestPoolSize; //用来记录线程池中曾经出现过的最大线程数
private long completedTaskCount; //用来记录已经执行完毕的任务个数
3. 线程池中的线程初始化
prestartCoreThread():初始化一个核心线程;
prestartAllCoreThreads():初始化所有核心线程
4. 任务缓存队列及排队策略
//任务缓存队列,用来存放等待执行的任务
private final BlockingQueue<Runnable> workQueue;
【排队策略】:
- ArrayBlockingQueue : 基于数组的先进先出阻塞队列,必须指定数组大小
- LinkedBlckingQueue: 基于链表 ,默认大小为Integer.MaxValue
- synchronousQueue: 这个比较特殊,不会保存任务,直接创建线程执行任务。
5. 任务拒绝策略
【任务拒绝的前提】: 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize
【任务拒绝策略】:
- ThreadPoolExecutor.AbortPolicy //丢弃任务并抛出RejectedExecutionException异常。
- DiscardPolicy //丢弃任务,但不抛出异常
- DiscardOldestPolicy //丢弃队列最前的任务,尝试重新执行任务
- CallerRunsPolicy //由调用线程执行该任务
6. 线程池的关闭
- shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
- shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
7. 线程池容量的动态调整
ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),
- setCorePoolSize:设置核心池大小
- setMaximumPoolSize:设置线程池最大能创建的线程数目大小
线程池最佳数量计算
实战
线程池 | 配置及持久化异常日志