一、什么是ThreadPoolExecutor
ThreadPoolExecutor是一个线程池,最多可使用7个参数来控制线程池的生成。
使用线程池可以避免创建和销毁线程的资源损耗,提高响应速度,并且可以管理线程池中线程的数量和状态等等。
阿里巴巴手册中也推荐使用该线程池,因为Executors创建缓存线程池时,最大线程数是Integer.MAX_VALUE
,可能导致堆栈溢出。而且使用ThreadPoolExecutor创建线程池可以让开发者更好理解线程池原理。
二、使用线程池的优点
1.减少系统资源消耗
无须重复创建和销毁线程,减少了线程创建和销毁造成的资源消耗。
2.提高响应速度
创建好的线程会驻留在线程池中,无需创建新线程执行任务,因而提高了响应速度。
3.提高了线程的可管理性。
线程池可以控制线程的数量,可以选择拒绝策略,可以监控和管理线程的状态,控制并发量等等。
这些都是自己创建线程难以做到的。
三、线程池原理
3.1 线程池的7个参数
1)corePoolSize 核心线程数
线程池常驻线程数量
2)maximumPoolSize 最大线程数
最大可存在的线程数量
3)keepAliveTime 非核心线程的存活时间
非核心线程空闲时,可以停留的时间
4)unit 存活时间的单位
非核心线程空闲时,可以停留的时间的单位
5)workQueue 阻塞队列
线程都在使用中时,可以将任务保存在阻塞队列中,可以设置队列的长度。
6)threadFactory 线程创建工厂
可以选择创建线程的工厂
7)handler 拒绝策略
当线程池无法存放更多任务时,处理这些过多的任务的策略
3.2 线程池执行任务的流程
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//判断工作线程数是否小于核心线程数
if (workerCountOf(c) < corePoolSize) {
//是,创建一个新线程
if (addWorker(command, true))
return;
c = ctl.get();
}
//否,将任务尝试添加到阻塞队列中,如果队列满了则会添加失败。
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//判断线程池状态是否在运行中,不在运行中时,删除该任务
if (! isRunning(recheck) && remove(command))
//不在运行中时,执行拒绝策略
reject(command);
//判断工作线程数是否为0
else if (workerCountOf(recheck) == 0)
//为0的场合,尝试创建新线程
addWorker(null, false);
}
//添加失败的场合,尝试创建一个新线程
else if (!addWorker(command, false))
//如果添加失败,执行拒绝策略
reject(command);
}
- 当执行一个任务时,首先会判断工作线程数是否小于核心线程数。
1.1. 如果小于核心线程数,则创建一个新线程来执行该任务。执行完毕。 - 如果大于核心线程数,则尝试将任务放入阻塞队列中。
2.1. 如果成功放入阻塞队列,待有空闲的线程时,空闲线程会从阻塞队列中获取任务并执行。执行完毕。 - 如果放入失败,表示阻塞队列已满,此时会尝试创建一个新线程来执行该任务。
3.1. 如果当前线程数小于最大线程数,则会创建新线程来执行该任务。执行完毕。
3.2. 如果工作线程数等于最大线程数,则不会创建新线程,尝试创建失败。此时会执行拒绝策略。执行完毕。
四、Executors提供的常用线程池
4.1 Executors.newFixedThreadPool
一个固定数量的线程池,可以通过传入的参数int nThreads
来控制线程池的线程数量。(核心线程数和最大线程数相同)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
4.2 Executors.newSingleThreadExecutor
一个线程数只有1的线程池。可以保证任务的顺序执行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
4.3 Executors.newCachedThreadPool
缓存线程池,新创建的线程会在该线程池中缓存60秒。可以提高短期异步任务的性能。
注意,最大线程数是Integer.MAX_VALUE
,高并发的场合下,可能会创建大量线程。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
4.4 Executors.newScheduledThreadPool
定时任务线程池,使用该线程池可以定时执行任务。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}