文章目录
- 前言
- 一、前言
- 1、ThreadPoolTaskExecutor
- 2、SimpleAsyncTaskExecutor
- 3、测试代码
- 二、各种情况模拟
- 1、未配置线程池
- 2、配置异步线程池
- 3、配置1个或多个非异步线程池
- 4、同时配置异步和非异步线程池
- 三、总结
前言
本文的目的,主要是看到网上各种说辞,抄来抄去,说异步方法不配置线程池会出现大问题等等,通过实验,来证明不同情况下,执行异步方法,使用的线程来自于什么线程池,来纠正大家以往的认知
一、前言
1、ThreadPoolTaskExecutor
源码如下,核心线程数为1,最大线程数和队列容量为Integer.MAX_VALUE
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
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;
...
}
2、SimpleAsyncTaskExecutor
/**
* {@link TaskExecutor} implementation that fires up a new Thread for each task,
* executing it asynchronously.
*
* <p>Supports limiting concurrent threads through the "concurrencyLimit"
* bean property. By default, the number of concurrent threads is unlimited.
*
* <p><b>NOTE: This implementation does not reuse threads!</b> Consider a
* thread-pooling TaskExecutor implementation instead, in particular for
* executing a large number of short-lived tasks.
*/
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
implements AsyncListenableTaskExecutor, Serializable {
....
}
以上是部分源码,大概意思就是会为每个任务启动一个新线程,异步执行它,可以通过 “concurrencyLimit” bean属性限制并发线程,默认情况下,并发线程数不受限制,比较适用于执行大量短期任务
3、测试代码
我们通过快速请求12次以下方法来看看执行情况
@Async
@Override
public void doAsyc() throws InterruptedException {
System.out.println("我是异步方法,线程名:" + Thread.currentThread().getName());
Thread.sleep(1000);
}
二、各种情况模拟
我们通过模拟项目中未配置线程池,配置了异步线程池,配置了非异步线程池,以及两种线程池组合来分析下
1、未配置线程池
运行结果如下:
我是异步方法,线程名:task-4
我是异步方法,线程名:task-5
我是异步方法,线程名:task-6
我是异步方法,线程名:task-3
我是异步方法,线程名:task-2
我是异步方法,线程名:task-1
我是异步方法,线程名:task-8
我是异步方法,线程名:task-7
我是异步方法,线程名:task-2
我是异步方法,线程名:task-4
我是异步方法,线程名:task-6
我是异步方法,线程名:task-5
通过上面结果,看不出来到底是使用哪个线程池?我们通过打断点来看看
通过debug,可以发现使用的ThreadPoolTaskExecutor线程池,corePoolSize=8,maxPoolSize、queueCapacity=Integer.MAX_VALUE
2、配置异步线程池
异步线程池
@Configuration
@EnableAsync
public class ForlanAsyncConfig implements AsyncConfigurer {
private int corePoolSize = 3;
private int maxPoolSize = 3;
private int queueCapacity = 10;
@Bean
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("forlan-async-thread-pool");
executor.initialize();
return TtlExecutors.getTtlExecutor(executor);
}
}
运行结果如下:
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool1
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool1
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool1
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool1
通过debug,发现使用的是我们自定义的异步线程池
3、配置1个或多个非异步线程池
非异步线程池1
@Configuration
@EnableAsync
public class Forlan1ThreadPoolConfig {
private int corePoolSize = 1;
private int maxPoolSize = 1;
private int queueCapacity = 10;
@Bean
public Executor forlan1ThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("forlan1-thread-pool");
executor.initialize();
return TtlExecutors.getTtlExecutor(executor);
}
}
非异步线程池2
@Configuration
@EnableAsync
public class Forlan2ThreadPoolConfig {
private int corePoolSize = 2;
private int maxPoolSize = 2;
private int queueCapacity = 10;
@Bean
public Executor forla2ThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("forlan2-thread-pool");
executor.initialize();
return TtlExecutors.getTtlExecutor(executor);
}
}
运行结果如下:运行了12个任务,创建了12个线程执行
我是异步方法,线程名:SimpleAsyncTaskExecutor-1
我是异步方法,线程名:SimpleAsyncTaskExecutor-3
我是异步方法,线程名:SimpleAsyncTaskExecutor-2
我是异步方法,线程名:SimpleAsyncTaskExecutor-4
我是异步方法,线程名:SimpleAsyncTaskExecutor-6
我是异步方法,线程名:SimpleAsyncTaskExecutor-7
我是异步方法,线程名:SimpleAsyncTaskExecutor-5
我是异步方法,线程名:SimpleAsyncTaskExecutor-8
我是异步方法,线程名:SimpleAsyncTaskExecutor-9
我是异步方法,线程名:SimpleAsyncTaskExecutor-11
我是异步方法,线程名:SimpleAsyncTaskExecutor-10
我是异步方法,线程名:SimpleAsyncTaskExecutor-12
通过debug,发现使用的SimpleAsyncTaskExecutor线程池,就是来一个任务创建一个线程
4、同时配置异步和非异步线程池
运行结果如下:
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool1
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool1
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool1
我是异步方法,线程名:forlan-async-thread-pool2
我是异步方法,线程名:forlan-async-thread-pool3
我是异步方法,线程名:forlan-async-thread-pool1
通过debug,发现使用的是我们自定义的异步线程池
三、总结
- 未配置线程池,使用的是默认的ThreadPoolTaskExecutor,corePoolSize=8,maxPoolSize、queueCapacity=Integer.MAX_VALUE
- 配置异步线程池:使用的是我们自定义的异步线程池
- 配置1个或多个非异步线程池:使用的是SimpleAsyncTaskExecutor,来一个任务创建一个新线程执行
- 同时配置异步和非异步线程池:使用的是我们自定义的异步线程池