为什么要学习线程池?
什么是线程池?
线程池的目的
创建线程池的方法
源码分析
Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的创建线程方法其实也只是ThreadPoolExecutor的构造函数参数不同而已,所有先分析ThreadPoolExecutor构造函数中各个参数的意思:
public ThreadPoolExecutor(int corePoolSize, // 核心线程池数量
int maximumPoolSize, // 最大线程数量
long keepAliveTime, // 表示线程没有任务执行时(空闲线程)的存活时间。
TimeUnit unit, // 参数keepAliveTime的时间单位
BlockingQueue<Runnable> workQueue,// 阻塞队列
ThreadFactory threadFactory // 每个线程创建的地方
) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
1.newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, // 没有核心线程
Integer.MAX_VALUE, // 最大线程数无上限
60L, // 空闲线程的存活时间为60秒,超过后就会被回收
TimeUnit.SECONDS, // 时间单位为秒
new SynchronousQueue<Runnable>());// 该队列的作用就是传递任务,但不会保存
}
可缓存线程池的特点:
- 没有核心线程,直接向队列中提交任务
- 如果有空闲线程,就去取出任务执行;如果没有空闲线程,就新建一个线程之后再去取出任务执行
- 执行完任务的空闲线程有 60 秒生存时间,如果在这个时间内可以接到新任务,就可以继续活下去,否则就被回收
2.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());// 该队列的默认容量为Integer.MAX_VALUE,相当于没有上限
}
定长线程池的特点:
- 核心线程数和最大线程数都是指定值,当线程池中的线程数超过核心线程数后,任务都会被放到阻塞队列中。
- 由于该阻塞队列容量非常大,可以一直加
- 执行完任务的线程反复去队列中取任务执行
3.newScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
定期线程池的特点:
- ScheduledThreadPoolExecutor继承自ThreadPoolExecutor类,所以执行super构造方法调用的是ThreadPoolExecutor构造函数
- 当调用ScheduledThreadPoolExecutor 的 scheduleAtFixedRate() 方法(按某种速率周期执行)或者 scheduleWithFixedDelay() 方法(在某个延迟后执行)时,会向ScheduledThreadPoolExecutor 的 DelayQueue 添加一个实现了 RunnableScheduledFutur 接口的ScheduledFutureTask
- 线程池中的线程从 DelayQueue 中获取 ScheduledFutureTask, 然后执行任务
4.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
单线程化的线程池的特点:
- 核心线程数和最大线程数都是1
- 线程池中没有线程时,新建一个线程执行任务
- 当线程数超过核心线程数以后,将任务添加到阻塞队列中
- 唯一的这一个线程不停地去队列里取任务执行
线程池的使用场景