ThreadPoolTaskExecutor源码

Image by Oleg Osadchuk from Pixabay

前言

最近在面试中被问到了这个区别,没回答得很好,刚好这一块涉及到了spring的异步任务,就好好的来总结一下关于源码的一些东西。

正文

这个类是spring框架的下的一个类,这个类是对jdk自带的ThreadPoolExecutor进行了封装。 他的底层实现还是jdkThreadPoolExecutor

构造方法

这个类没有构造方法,使用默认的构造方法。

属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

    // 监视器锁,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还提供了上面参数的setget方法。

方法

ThreadPoolTaskExecutor执行任务都是调用的ThreadPoolExecutor来执行任务的,这里就不细说了。

initializeExecutor方法

这个方法被ThreadPoolTaskExecutor进行了重写,而这个方法是ExecutorConfigurationSupport类的一个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

    @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中该接口的源码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

    // 父类中的接口
    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被容器初始化完成后调用。 也就是ThreadPoolTaskExecutorinitializeExecutor方法是容器初始化该bean后会自动调用该方法,所以不用手动调用。

总结:
我们虽然在创建ThreadPoolTaskExecutor时,未创建ThreadPoolExecutor; 网上有的博客还说在创建ThreadPoolTaskExecutor时,需要手动去调用initializeExecutor方法,个人觉得这个是有歧义的, 具体需不需要手动调用初始化方法,是要看自己怎么去利用ThreadPoolTaskExecutor的,假如是将其作为bean放入容器的,则不需要手动调用。若未加入容器,二十自己手动进行管理,则需要手动调用。

下面是createQueue方法代码

1
2
3
4
5
6
7
8
9
10

    protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
		if (queueCapacity > 0) {
			return new LinkedBlockingQueue<>(queueCapacity);
		}
		else {
			return new SynchronousQueue<>();
		}
	}
	

这里需要注意的是,ThreadPoolTaskExecutor队列默认参数是Integer.MAX_VALUE,这里具体怎么设置就根据自己的业务而定了

总结

ThreadPoolTaskExecutorThreadPoolExecutor的区别?

  1. ThreadPoolExecutor是jdk自带的线程池,ThreadPoolTaskExecutor是spring的
  2. ThreadPoolTaskExecutorThreadPoolExecutor进行了封装,具体任务自行还是使用的ThreadPoolExecutor
  3. 注意ThreadPoolTaskExecutor的一些默认参数,是需要修改的。
  4. 若是自定义的ThreadPoolTaskExecutor实例,且未加入容器中,则需要手动调用初始化方法,若是放入容器中的,则不需要手动调用初始化方法。
  5. ThreadPoolTaskExecutor使用了装饰器模式来对任务进行装饰,可以参考,面试中也有可能会遇到相关的问题
坚持原创技术分享,您的支持将鼓励我继续创作!