Spring中@Async
注解使用及配置
参考文章:https://blog.csdn.net/weixin_42272869/article/details/123082657
一、@Async
注解的使用
在使用spring框架中,可以非常简单方便的实现一个异步执行方法,具体只需要在启动类添加@EnableAsync
注解开启支持异步,然后在需要进行异步处理的方法上使用@Async
注解即可进行异步执行。
注意:想要异步执行,不能在一个类中直接调用本类中被@Async
注解标记的方法,本类中直接调用会同步执行,不会进行异步执行
主启动类
@EnableAsync//开启异步支持,也可以标记在被@Configuration注解标注的类上,效果一致
@SpringBootApplication
public class ApplicationTest{
....
}
使用实例:需要交给spring容器管理bean
@Component
public class MyAsyncService {
@Async//直接使用异步注解即可,默认使用的线程池就是自定义实现的线程池
public void testAsync(){
System.out.println("==== 我执行了 ====");
System.out.println("MyAsyncService.testAsync() = " + Thread.currentThread().getName());
}
}
测试执行:
/* 使用SpringBoot执行测试 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Resource
MyAsyncService myAsyncService;
@Test
void testTread(){
myAsyncService.testAsync();
System.out.println("结束.... " );
}
}
测试结果:
二、@Async
注解线程池的配置及使用
1、@Async默认线程池修改
对于修改@Async使用的默认线程池,我们可以使用实现AsyncConfigurer
接口,并重写getAsyncExecutor()方法,为其提供我们自己定义的线程池即可
具体示例:
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 描述:线程池配置类,修改@Async注解默认使用的线程池
*
* @author SXT
* @version 1.0
* @date 2022/11/22
*/
//开启自动启用异步注解,与配置类放在一起,方便管理
@EnableAsync
@Configuration
@Slf4j
public class AsyncTaskPoolConfig implements AsyncConfigurer {
/**
* 用于@Async注解获取默认线程连接池
* @return
*/
@Override
public Executor getAsyncExecutor() {
//此类由Spring提供,org.springframework.scheduling.concurrent包下,是线程池的封装类
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//线程池中线程的名字前缀
taskExecutor.setThreadNamePrefix("taskThreadPool-async-");
//线程池核心线程数量
taskExecutor.setCorePoolSize(5);
//线程池最大线程数量
taskExecutor.setMaxPoolSize(10);
//线程池空闲线程存活时间,单位秒
taskExecutor.setKeepAliveSeconds(100);
//线程池拒绝策略
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
//线程池任务队容量,如果不设置则默认 Integer.MAX_VALUE,
// 队列默认使用LinkedBlockingQueue 若queueCapacity的值 <= 0,则使用SynchronousQueue
taskExecutor.setQueueCapacity(1000);
//线程池中核心线程是否允许超时,默认为false
taskExecutor.setAllowCoreThreadTimeOut(true);
//线程池中的超时处理时间,单位秒,有一个对应方法为毫秒,默认为不超时
taskExecutor.setAwaitTerminationSeconds(60);
//初始化线程池,不可以少,否者会抛出 线程池没有初始化
taskExecutor.initialize();
return taskExecutor;
}
/**
* 线程未处理异常的统一处理机制,即线程池异常处理器,简单示例
* @return
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// 异常处理器函数接口类
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.error("============ " + throwable.getMessage() + " ===========", throwable);
log.error("============ " + method.getName() + " ===========", objects);
}
};
}
}
实现AsyncConfigurer
类中的getAsyncExecutor()方法后,在使用@Async注解进行异步执行时,默认使用的线程池就是实现提供的线程池,具体使用示例如下:
/**
* 描述:异步方法调用
*
* @author SXT
* @version 1.0
* @date 2022/11/23
*/
@Component
public class MyAsyncService {
@Async//直接使用异步注解即可,默认使用的线程池就是自定义实现的线程池
public void testAsync(){
System.out.println("==== 我执行了 ====");
System.out.println("MyAsyncService.testAsync() = " + Thread.currentThread().getName());
}
}
/* 使用SpringBoot执行测试 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Resource
MyAsyncService myAsyncService;
@Test
void testTread(){
myAsyncService.testAsync();
System.out.println("结束.... " );
}
}
测试执行结果如下:如实使用实现提供的线程池
2、自定义线程池(@Async指定使用自定义线程池)
无论是修改@Async默认提供的线程池还是不修改,都可以对某些使用@Async标注的异步执行方法为其指定使用具体的某一个线程池,若想要使用指定的线程池需要明确的为@Async注解指定使用的线程池名称(自定义的线程池需要交给Spring管理),也就是bean的名称
自定义线程池示例:可以看到与修改@Async默认线程池中提供线程池的内容一样,线程池具体的配置可以根据需求进行设置
@Configuration
public class CommentConfig {
/**
* 自定义异步线程池,bean的名字如果不显示的指定,则默认使用方法的名称作为bean的名称
* @return
*/
@Bean("asyncTaskPool")
public Executor asyncTaskPool(){
//此类由Spring提供,org.springframework.scheduling.concurrent包下,是线程池的封装类
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//线程池中线程的名字前缀
executor.setThreadNamePrefix("asyncTaskPool-task-");
//线程池核心线程数量
executor.setCorePoolSize(5);
//线程池最大线程数量
executor.setMaxPoolSize(10);
//线程池空闲线程存活时间,单位秒
executor.setKeepAliveSeconds(100);
//线程池拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//线程池任务队容量,如果不设置则默认 Integer.MAX_VALUE,
// 队列默认使用LinkedBlockingQueue 若queueCapacity的值 <= 0,则使用SynchronousQueue
executor.setQueueCapacity(1000);
//线程池中核心线程是否允许超时,默认为false
executor.setAllowCoreThreadTimeOut(true);
//线程池中的超时处理时间,单位秒,有一个对应方法为毫秒,默认为不超时
executor.setAwaitTerminationSeconds(60);
//初始化线程池,不可以少,否者会抛出 线程池没有初始化
executor.initialize();
return executor;
}
}
使用自定义线程池示例:
/**
* 描述:异步方法调用
*
* @author SXT
* @version 1.0
* @date 2022/11/23
*/
@Component
public class MyAsyncService {
//指定使用线程池的bean的名称,不指定的话使用的是默认提供的线程池
//asyncTaskPool就是被Spring管理的线程池实例的对象名称
@Async("asyncTaskPool")
public void testAsync2(){
System.out.println("==== 我执行了 ====");
System.out.println("MyAsyncService.testAsync2() = " + Thread.currentThread().getName());
}
}
/* 使用SpringBoot执行测试 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Resource
MyAsyncService myAsyncService;
@Test
void testTread2(){
myAsyncService.testAsync2();
System.out.println("结束.... " );
}
}
测试结果如下:
拓展:
若想要根据配置文件进行动态的配置自定义线程池,则可以使用如下方式
配置文件properties文件或yml文件
#这里使用properties文件进行配置,yml文件同样的方式,只是格式不同
#也可以将驼峰命名改成core-size ,keep-alive-seconds,对应的实体类依旧是驼峰命名
asyncTask.pool.coreSize=5
asyncTask.pool.maxPoolSize=10
asyncTask.pool.keepAliveSeconds=60
asyncTask.pool.queueCapacity=1000
asyncTask.pool.timeOutSeconds=60
定义获取配置文件对应配置的类
/**
* 描述:线程池配置文件实体类
*
* @author SXT
* @version 1.0
* @date 2022/11/23
*/
//使用@ConfigurationProperties注解,其类必须交给Spring管理
@ConfigurationProperties(prefix = "async-task.pool")
@Component
@ToString
@Data
public class ThreadConfig {
private int coreSize;
private int maxPoolSize;
private long keepAliveSeconds;
private int queueCapacity;
private long timeOutSeconds;
}
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Autowired
ThreadConfig threadConfig;
@Test
void testProperties1(){
System.out.println("threadConfig = " + threadConfig);
}
}
测试结果:
提示:配置的key不要写错,不然获取不到值
三、@Async
注解的原理
待完善
标签:异步,Spring,public,线程,Async,注解,class From: https://www.cnblogs.com/qiushuiyu-108/p/16940205.html