本文通过对 Executors 源码进行分析,介绍了JDK中各种默认线程池的原理以及适用场景,为如何设置线程池参数提供一定的参考。
newFixedThreadPool
- 定义
/**
* ......
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- 创建可容纳固定数量(nThreads)线程的线程池;
- 每个线程的存活时间不限(0L),当线程池满后不在添加新的线程;
- 如果线程池中所有线程都处于繁忙状态,新的任务将会进入阻塞队列(LinkedBlockingQueue);
newSingleThreadExecutor
/**
*......
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
- 创建一个只有一个线程的线程池;
- 每个线程存活时间不限(0L);
- 如果该线程处于繁忙状态,新的任务将会进入阻塞队列(LinkedBlockingQueue);
适用场景:一个任务一个任务执行的场景
newCachedThreadPool
/**
* ......
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- 创建一个可缓存线程池
- 如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
ScheduledThreadPoolExecutor
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
- 创建一个定长线程池,支持定时及周期性任务执行。
当我们使用完成ExecutorService之后应该关闭它,否则它里面的线程会一直处于运行状态。
举个例子,如果的应用程序是通过main()方法启动的,在这个main()退出之后,如果应用程序中的ExecutorService没有关闭,这个应用将一直运行。之所以会出现这种情况,是因为ExecutorService中运行的线程会阻止JVM关闭。
如果要关闭ExecutorService中执行的线程,我们可以调用ExecutorService.shutdown()方法。在调用shutdown()方法之后,ExecutorService不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。
如果我们想立即关闭ExecutorService,我们可以调用ExecutorService.shutdownNow()方法。这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。
Q.E.D.