1、通过Executors创建线程池的四种方式
1)创建单个线程的线程池
该线程池使用单个线程在无界工作队列中执行任务,如果此单个线程在执行过程中由于故障而终止,则会分配一个新的线程来执行后续的任务。工作列队中的任务保证按顺序执行,并且保证在任意时刻都不会有多个任务处于活动状态。与newFixedThreadPool(1)返回的执行器不同,newSingleThreadExecutor()不允许重新配置线程数以使用多个线程。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
2)创建指定线程数的线程池
线程池在无界队列中运行固定数量的线程来执行任务,任何时候活跃的执行任务数都跟分配的固定数量线程数相等,如果所有线程都处于活跃状态,那么新提交的任务会在队列中等待,直到有线程可用。如果有线程在执行过程中由于失败而终止,那么会有新的线程来代替它。池中的线程会一直存在,直到它显式关闭。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
3)创建可缓存线程的线程池
该线程池根据需要创建新线程,如果有任务需要执行时,会优先分配以前创建的空闲线程,没有的空闲线程的时候才会创建新线程到池中执行任务。通常可以提高执行许多短期异步任务的程序的性能。超过60秒未使用的线程会被终止并从缓存中删除,因此空闲时间足够长的池不会消耗任何资源。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
4)创建可调度线程池
该线程池可以延时或定期执行任务。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
2、ThreadPoolExecutor构造器
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
Executors的工厂方法创建的线程池底层都是通过ThreadPoolExecutor来创建的,这个构造器的每个参数定义了每个线程池的工作特性。
corePoolSize:线程池中保留的核心线程数,即使处于空闲状态,除非设置了threadPoolExecutor.allowCoreThreadTimeOut(true);
maximumPoolSize:线程池中允许的最大线程数
keepAliveTime:当线程数大于核心数时,多余的空闲线程在终止前等待新任务的最长时间
unit:keepAliveTime的时间单位
workQueue:用于执行任务之前保存任务的阻塞队列,这个队列只会保存通过execute提交的Runnable任务
threadFactory:线程池创建新线程时的线程工厂
handler:拒绝执行器,用于任务达到线程边界和队列容量而拒绝执行的处理器
3、newSingleThreadExecutor
1)底层通过ThreadPoolExecutor创建,再由FinalizableDelegatedExecutorService封装,FinalizableDelegatedExecutorService的父类是DelegatedExecutorService,他们两个都是Executors的静态内部类,所以是没有allowCoreThreadTimeOut方法来让核心线程回收,并且也无法通过setCorePoolSize(int corePoolSize)方法来重新设置核心线程数的。
static class FinalizableDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
protected void finalize() {
super.shutdown();
}
}
2)默认核心线程数和最大线程数都是1,线程空闲最大时间为0,因为没有最大线程和核心线程一致,所以没有多余的超出核心线程数的空闲线程,默认配置的工作队列是LinkedBlockingQueue,没有指定容量默认最大值为Integer.MAX_VALUE。线程工厂和拒绝处理器使用的是默认的。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// 底层调用的构造器是下面这个
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
3)默认线程工厂是Executors的静态内部类,创建默认线程工厂构造器
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
4)默认任务拒绝执行器是ThreadPoolExecutor的静态静态内部类,默认策略是当任务超过线程池的最大线程数量和工作队列的容量时,默认会抛出RejectedExecutionException异常。
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
5)RejectedExecutionHandler的所有实现
当任务数量超过最大线程数和工作列队容量时,各个拒绝处理器实现类的拒绝策略如下:
AbortPolicy :抛出RejectedExecutionException异常
CallerRunsPolicy:直接使用调用execute方法的线程来执行任务,除非线程池关闭,此时任务会丢弃
DiscardOldestPolicy:丢弃最早未被执行的任务,放入新添加的任务到工作队列中,除非线程池关闭,此时任务会丢弃
DiscardPolicy:直接丢失当前被拒绝任务。
tips:除了使用JDK提供的四种自带的拒绝策略,也可以添加自定义的实现来作为任务拒绝执行策略。
4、newFixedThreadPool
看源码可以知道核心线程数和最大线程数都是传入的nThreads数量,其他配置是跟newSingleThreadExecutor一样的
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
5、newCachedThreadPool
1)核心线程数量为0,最大线程数为Integer.MAX_VALUE
2)当有新任务执行时,如果没有空闲线程,则会创建新线程执行
3)如果线程执行完任务超过60秒没有新的任务执行,那么线程会被终止回收
4)工作队列不同上面的线程池是使用的SynchronousQueue,不同于LinkedBlockingQueue底层依赖ReentranLock(内部的静态内部类Sync实现AQS,即AbstractQueuedSynchronizer),SynchronousQueue是无缓冲等待队列,内部没有容量,每个插入操作都必须等待另一个线程执行相应的删除操作,而且必须等队列中的元素被消费后才能继续添加新的元素。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
6、newScheduledThreadPool
1)使用ScheduledThreadPoolExecutor来创建线程池,实际上还是使用父类ThreadPoolExecutor
2)不同的是工作队列使用的是DelayedWorkQueue,是ScheduledThreadPoolExecutor的静态内部类,是专用的延迟队列。
3)DelayedWorkQueue基于堆结构的等待队列
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}