1.使用
1.1 SpringBootApplication 启动类或者配置类中添加@EnableAsync 注解。
1.2 在需要异步执行的方法中加上@Async 注解。
注意:
@Async 注解应该用在“public”方法上。
@Async 注解所在的类应该被 Spring 容器管理。
@Async 注解作用的方法,被调用的时候需要被Spring动态代理到,同类方法不能直接用this.xxx()调用否则不生效。
@EnableAsync
@SpringBootApplication
public class DemoAsyncApplication {
public static void main(String[] args) {
SpringApplication.run(DemoAsyncApplication.class, args);
}
}
@Slf4j
@Service
public class AsyncService {
@Async
public void test(){
try {
TimeUnit.SECONDS.sleep(1);
log.info(Thread.currentThread().getName()+"AsyncService");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
2.实现
@Async 注解 的默认使用的是bean name为”taskExecutor“,核心线程数为8,最大线程数为Integer.MAX_VALUE,阻塞队列为LinkedBlockingQueue,阻塞队列的大小Integer.MAX_VALUE,为线程空闲超时时间为60秒。
public static class Pool {
/**
* Queue capacity. An unbounded capacity does not increase the pool and therefore
* ignores the "max-size" property.
*/
private int queueCapacity = Integer.MAX_VALUE;
/**
* Core number of threads.
*/
private int coreSize = 8;
/**
* Maximum allowed number of threads. If tasks are filling up the queue, the pool
* can expand up to that size to accommodate the load. Ignored if the queue is
* unbounded.
*/
private int maxSize = Integer.MAX_VALUE;
/**
* Whether core threads are allowed to time out. This enables dynamic growing and
* shrinking of the pool.
*/
private boolean allowCoreThreadTimeout = true;
/**
* Time limit for which threads may remain idle before being terminated.
*/
private Duration keepAlive = Duration.ofSeconds(60);
使用的默认线程是在配置类TaskExecutionAutoConfiguration 里配置的。
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}.
*
* @author Stephane Nicoll
* @author Camille Vienot
* @since 2.1.0
*/
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {
/**
* Bean name of the application {@link TaskExecutor}.
*/
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
@Bean
@ConditionalOnMissingBean
public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
ObjectProvider<TaskDecorator> taskDecorator) {
TaskExecutionProperties.Pool pool = properties.getPool();
TaskExecutorBuilder builder = new TaskExecutorBuilder();
builder = builder.queueCapacity(pool.getQueueCapacity());
builder = builder.corePoolSize(pool.getCoreSize());
builder = builder.maxPoolSize(pool.getMaxSize());
builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
builder = builder.keepAlive(pool.getKeepAlive());
Shutdown shutdown = properties.getShutdown();
builder = builder.awaitTermination(shutdown.isAwaitTermination());
builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);
builder = builder.taskDecorator(taskDecorator.getIfUnique());
return builder;
}
@Lazy
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
}
使用用线程池去执行任务:
AsyncExecutionAspectSupport.java
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
Callable<Object> task = () -> {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
}
catch (ExecutionException ex) {
handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
}
catch (Throwable ex) {
handleError(ex, userDeclaredMethod, invocation.getArguments());
}
return null;
};
return doSubmit(task, executor, invocation.getMethod().getReturnType());
}
获取线程池,先看注解的value是否有值,有值则根据bean 那么获取线程池,否则从默认的线程池中获取。
@Nullable
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
AsyncTaskExecutor executor = this.executors.get(method);
if (executor == null) {
Executor targetExecutor;
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
}
else {
targetExecutor = this.defaultExecutor.get();
}
if (targetExecutor == null) {
return null;
}
executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
this.executors.put(method, executor);
}
return executor;
}
3.自定义@Async 的线程池
自定义@Async 的线程池有两种实现方式,第一种是自定义一个线程池,然后写在注解里 @Async(value = "asyncMarkValueExecutor")
;第二种是实现AsyncConfigurer
接口,重写getAsyncExecutor()
方法。
3.1 第一种方式
1.定义一个线程池,注入spring
@Bean(name = "asyncMarkValueExecutor")
public Executor asyncMarkValueExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(1000);
executor.setQueueCapacity(10000);
executor.setThreadNamePrefix("async-thread-pool-");
return executor;
}
2.将线程池的bean name加到注解里。
@Async(value = "asyncMarkValueExecutor")
public void test(){
try {
TimeUnit.SECONDS.sleep(1);
log.info(Thread.currentThread().getName()+"AsyncService");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
3.2 第二种方式
实现AsyncConfigurer
接口,重写getAsyncExecutor()
方法。
@Configuration
public class MyConfig implements AsyncConfigurer {
@Bean(name = "asyncExecutor")
public Executor asyncExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(2000);
executor.setQueueCapacity(10000);
executor.setThreadNamePrefix("my-thread-pool-");
return executor;
}
@Override
public Executor getAsyncExecutor() {
return asyncExecutor();
}
}
4.ThreadPoolTaskExecutor和ThreadPoolExecutor的区别
1. ThreadPoolTaskExecutor 是 Spring 框架提供的一个线程池实现,它是对 JDK 标准库中的 ThreadPoolExecutor 进行了封装和扩展。
2. ThreadPoolTaskExecutor比ThreadPoolExecutor更加方便使用和灵活。
2.1 ThreadPoolTaskExecutor有默认的参数,使用的时可以直接使用默认参数也可以设置参数。而ThreadPoolExecutor 需要显示的指定参数才能创建。
2.2 ThreadPoolTaskExecutor可以直接设置线程名称的前缀,以及是否为守护线程;
ThreadPoolExecutor则需要实例化一个ThreadFactory重写newThread来指定线程创建时候的属性。
ThreadPoolExecutor 示例:
ThreadFactory factory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("my-thread");
return thread;
}
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60, // 线程空闲时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(100), // 任务队列
factory, // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
3. ThreadPoolTaskExecutor与spring更加的契合。ThreadPoolTaskExecutor注入spring后,会被spring管理整个生命周期,包括初始化和线程池的销毁。
ThreadPoolTaskExecutor 会在属性填充完之后进行初始化,无需手动调用初始化方法,在bean销毁的时候会调用关闭线程池的方法:
ExecutorConfigurationSupport
public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory
implements BeanNameAware, InitializingBean, DisposableBean {
......
// 初始化线程池
@Override
public void afterPropertiesSet() {
initialize();
}
/**
* Set up the ExecutorService.
*/
public void initialize() {
if (logger.isDebugEnabled()) {
logger.debug("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (!this.threadNamePrefixSet && this.beanName != null) {
setThreadNamePrefix(this.beanName + "-");
}
this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
....
protected abstract ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler);
...
// 销毁线程池
@Override
public void destroy() {
shutdown();
}
/**
* Perform a shutdown on the underlying ExecutorService.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
public void shutdown() {
if (logger.isDebugEnabled()) {
logger.debug("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (this.executor != null) {
// 是否执行完等待中的任务,默认值为false
if (this.waitForTasksToCompleteOnShutdown) {
this.executor.shutdown();
}
// 取消线程池等待队列中的任务
else {
for (Runnable remainingTask : this.executor.shutdownNow()) {
cancelRemainingTask(remainingTask);
}
}
awaitTerminationIfNecessary(this.executor);
}
}
...
protected void cancelRemainingTask(Runnable task) {
if (task instanceof Future) {
((Future<?>) task).cancel(true);
}
}
...
}
ThreadPoolTaskExecutor
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
...
// 初始化线程池
@Override
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor;
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;
}
...
// 取消任务的执行
@Override
protected void cancelRemainingTask(Runnable task) {
super.cancelRemainingTask(task);
// Cancel associated user-level Future handle as well
Object original = this.decoratedTaskMap.get(task);
if (original instanceof Future) {
((Future<?>) original).cancel(true);
}
}
}
4. ThreadPoolTaskExecutor中的设置线程池有些属性的方法是线程安全的。
ThreadPoolTaskExecutor中设置线程池属性:corePoolSize、maxPoolSize、keepAliveSeconds这三个属性的方法加了synchronized关键字,而ThreadPoolExecutor则没有加。
public void setCorePoolSize(int corePoolSize) {
synchronized (this.poolSizeMonitor) {
if (this.threadPoolExecutor != null) {
this.threadPoolExecutor.setCorePoolSize(corePoolSize);
}
this.corePoolSize = corePoolSize;
}
}
5.线程池的预热
ThreadPoolExecutor的预热,可以调用两个方法:
1.prestartCoreThread 启动一个核心线程
public boolean prestartCoreThread() {
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
2.prestartAllCoreThreads 启动所有的核心线程
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
ThreadPoolTaskExecutor如何预热?
1.因为ThreadPoolTaskExecutor是对ThreadPoolExecutor的封装,所以ThreadPoolTaskExecutor的预热需要调用ThreadPoolExecutor的方法进行预热。
2.又因为ThreadPoolTaskExecutor是在属性填充完成后才进行初始化的,所以我们需要等待ThreadPoolTaskExecutor初始化完成之后才能获取ThreadPoolExecutor ,再调用预热的方法。
重写afterPropertiesSet()
方法,在初始化完成后获取ThreadPoolExecutor 进行预热:
@Configuration
public class MyConfig {
@Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(){
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
threadPoolExecutor.prestartAllCoreThreads();
int alive = threadPoolExecutor.getPoolSize();
System.out.println("启动线程数量:" + alive);
}
};
executor.setCorePoolSize(5);
executor.setMaxPoolSize(2000);
executor.setQueueCapacity(10000);
executor.setThreadNamePrefix("my-thread-pool-");
return executor;
}
}
输出:
启动线程数量:5