文章目录
- 前言
- 一、前言
- 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,来一个任务创建一个新线程执行
- 同时配置异步和非异步线程池:使用的是我们自定义的异步线程池



![[CVPR 2023] Imagic:使用扩散模型进行基于文本的真实图像编辑](https://img-blog.csdnimg.cn/img_convert/5c990ea9f7674e7e1bab2c127615339c.png)















