“This article has participated in the call for good writing activities, click to view: the back end, the big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!”
preface
Recently I was asked about this distinction in an interview and didn’t get a good answer. It happened to involve Spring’s asynchronous tasks, so I did a good job summarizing some of the source code.
The body of the
This class is a component of the Spring framework that encapsulates the JDK’s built-in ThreadPoolExecutor. Its underlying implementation is the JDK’s ThreadPoolExecutor.
A constructor
This class has no constructor and uses the default constructor.
attribute
// Monitor lock, synchronized uses this object as the lock object
private final Object poolSizeMonitor = new Object();
// Number of core threads
private int corePoolSize = 1;
// Maximum number of threads
private int maxPoolSize = Integer.MAX_VALUE;
// Thread lifetime
private int keepAliveSeconds = 60;
// Initialize the queue capacity
private int queueCapacity = Integer.MAX_VALUE;
// Whether the number of core threads has idle time
private boolean allowCoreThreadTimeOut = false;
@Nullable // Task decorator
private TaskDecorator taskDecorator;
@Nullable / / thread pool
private ThreadPoolExecutor threadPoolExecutor;
Copy the code
These are the default parameters for ThreadPoolTaskExecutor. The above parameter has fewer reject policy parameters than ThreadPoolExecutor. Of course, ThreadPoolTaskExecutor also provides set and GET methods for the above arguments.
methods
ThreadPoolTaskExecutor executes tasks by calling ThreadPoolExecutor instead of going into detail here.
InitializeExecutor method
This method is ThreadPoolTaskExecutor rewrites the, and this method is ExecutorConfigurationSupport an interface of a class.
@Override
protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
// Create a blocking queue
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor;
// If the decorator is not empty, override the execute method of ThreadPoolExecutor to decorate the task (decorator mode)
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;
}
Copy the code
The above source code is not too difficult, as you can easily see if you have seen the ThreadPoolExecutor source code. The initial rejection policy parameters are passed in here, and everything else is available in ThreadPoolTaskExecutor.
This method also uses the decorator pattern, which can be noted here, and the source code for the decorator implementation is relatively simple.
Take a look at the source of the interface in the superclass ExecutorConfigurationSupport:
// Interface in the parent class
protected abstract ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler);
This method calls the initializeExecutor method
public void initialize(a) {
if (logger.isInfoEnabled()) {
logger.info("Initializing ExecutorService" + (this.beanName ! =null ? "'" + this.beanName + "'" : ""));
}
if (!this.threadNamePrefixSet && this.beanName ! =null) {
setThreadNamePrefix(this.beanName + "-");
}
/ / here's refusal strategies used by default new ThreadPoolExecutor AbortPolicy ();
this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
// This method will be called after the bean is initialized
@Override
public void afterPropertiesSet(a) {
Call the initialize method
initialize();
}
Copy the code
ExecutorConfigurationSupport afterPropertiesSet implementing the InitializingBean interface methods. This method is called after the bean has been initialized by the container. The initializeExecutor method of ThreadPoolTaskExecutor is automatically called after the container initializes the bean, so it is not called manually.
Summary: Although we did not create ThreadPoolExecutor when we created ThreadPoolTaskExecutor; InitializeExecutor (ThreadPoolTaskExecutor) initializeExecutor (ThreadPoolTaskExecutor) It depends on how you use ThreadPoolTaskExecutor. If you put it into the container as a bean, you don’t need to call it manually. If 20 is not added to the container, it needs to be manually invoked.
Here is the code for the createQueue method
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
if (queueCapacity > 0) {
return new LinkedBlockingQueue<>(queueCapacity);
}
else {
return newSynchronousQueue<>(); }}Copy the code
Note that the default parameter of the ThreadPoolTaskExecutor queue is integer. MAX_VALUE, which depends on your business
conclusion
How does ThreadPoolTaskExecutor differ from ThreadPoolExecutor?
ThreadPoolExecutor
Is the JDK’s own thread pool,ThreadPoolTaskExecutor
Is springThreadPoolTaskExecutor
rightThreadPoolExecutor
Carried on the encapsulation, the specific task is still used by itselfThreadPoolExecutor
- Pay attention to
ThreadPoolTaskExecutor
Some of the default parameters of the. - If it is custom
ThreadPoolTaskExecutor
Instance, and is not added to the container, need to call the initialization method manually, if added to the container, do not need to call the initialization method manually. ThreadPoolTaskExecutor
The decorator mode is used to decorate the tasks, which can be referred to as related questions may be encountered in the interview