前言
最近在面试中被问到了这个区别,没回答得很好,刚好这一块涉及到了spring
的异步任务,就好好的来总结一下关于源码的一些东西。
正文
这个类是spring
框架的下的一个类,这个类是对jdk自带的ThreadPoolExecutor
进行了封装。 他的底层实现还是jdk
的ThreadPoolExecutor
。
构造方法
这个类没有构造方法,使用默认的构造方法。
属性
// 监视器锁,synchronized使用该对象作为锁对象
private final Object poolSizeMonitor = new Object();
// 核心线程数量
private int corePoolSize = 1;
// 最大线程数量
private int maxPoolSize = Integer.MAX_VALUE;
// 线程存活时间
private int keepAliveSeconds = 60;
// 队列初始化容量
private int queueCapacity = Integer.MAX_VALUE;
// 核心线程数是否有空闲时间
private boolean allowCoreThreadTimeOut = false;
@Nullable //任务装饰器
private TaskDecorator taskDecorator;
@Nullable // 线程池
private ThreadPoolExecutor threadPoolExecutor;
以上参数是ThreadPoolTaskExecutor
的默认参数。
上面的参数相对ThreadPoolExecutor
来说,少了拒绝策略参数。
当然,ThreadPoolTaskExecutor
还提供了上面参数的set
和get
方法。
方法
ThreadPoolTaskExecutor
执行任务都是调用的ThreadPoolExecutor
来执行任务的,这里就不细说了。
initializeExecutor方法
这个方法被ThreadPoolTaskExecutor
进行了重写,而这个方法是ExecutorConfigurationSupport
类的一个接口。
@Override
protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
// 创建阻塞队列
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor;
// 若装饰器不为空,重写ThreadPoolExecutor的execute方法,对任务进行装饰(装饰器模式)
if (this.taskDecorator != null) {
executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,queue, threadFactory, rejectedExecutionHandler) {
@Override
public void execute(Runnable command) {
Runnable decorated = taskDecorator.decorate(command);
if (decorated != command) {
decoratedTaskMap.put(decorated, command);
}
super.execute(decorated);
}
};
}
else {
executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, threadFactory, rejectedExecutionHandler);
}
if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true);
}
this.threadPoolExecutor = executor;
return executor;
}
上面的源码也不算难,看过ThreadPoolExecutor
源码的就很容易看出来了。
最开始提到的拒绝策略参数是在这里传入的,除此之外的参数都是ThreadPoolTaskExecutor
中有的。
这个方法还用到了装饰器模式,这里可以标注一下,装饰器实现的的源码也比较简单。
下面来看看父类ExecutorConfigurationSupport
中该接口的源码吧:
// 父类中的接口
protected abstract ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler);
// 该方法调用了initializeExecutor方法
public void initialize() {
if (logger.isInfoEnabled()) {
logger.info("Initializing ExecutorService" + (this.beanName != null ? " ‘" + this.beanName + "‘" : ""));
}
if (!this.threadNamePrefixSet && this.beanName != null) {
setThreadNamePrefix(this.beanName + "-");
}
// 这里的拒绝策略默认使用new ThreadPoolExecutor.AbortPolicy();
this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
// 看到这个方法,就知道该方法在bean初始化完成后会被调用
@Override
public void afterPropertiesSet() {
// 调用initialize方法
initialize();
}
ExecutorConfigurationSupport
实现InitializingBean
接口的afterPropertiesSet
方法。
该方法会在bean被容器初始化完成后调用。
也就是ThreadPoolTaskExecutor
的initializeExecutor
方法是容器初始化该bean后会自动调用该方法,所以不用手动调用。
总结:
我们虽然在创建ThreadPoolTaskExecutor
时,未创建ThreadPoolExecutor
;
网上有的博客还说在创建ThreadPoolTaskExecutor
时,需要手动去调用initializeExecutor
方法,个人觉得这个是有歧义的,
具体需不需要手动调用初始化方法,是要看自己怎么去利用ThreadPoolTaskExecutor
的,假如是将其作为bean放入容器的,则不需要手动调用。若未加入容器,二十自己手动进行管理,则需要手动调用。
下面是createQueue
方法代码
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
if (queueCapacity > 0) {
return new LinkedBlockingQueue<>(queueCapacity);
}
else {
return new SynchronousQueue<>();
}
}
这里需要注意的是,ThreadPoolTaskExecutor
队列默认参数是Integer.MAX_VALUE
,这里具体怎么设置就根据自己的业务而定了
总结
ThreadPoolTaskExecutor
与ThreadPoolExecutor
的区别?
-
ThreadPoolExecutor
是jdk自带的线程池,ThreadPoolTaskExecutor
是spring的 -
ThreadPoolTaskExecutor
对ThreadPoolExecutor
进行了封装,具体任务自行还是使用的ThreadPoolExecutor
- 注意
ThreadPoolTaskExecutor
的一些默认参数,是需要修改的。 - 若是自定义的
ThreadPoolTaskExecutor
实例,且未加入容器中,则需要手动调用初始化方法,若是放入容器中的,则不需要手动调用初始化方法。 -
ThreadPoolTaskExecutor
使用了装饰器模式来对任务进行装饰,可以参考,面试中也有可能会遇到相关的问题