我们在使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,在使用spring中,已经给我们做了很好的支持。只要要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。
默认情况下,Spring将搜索相关的线程池定义:要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean。如果两者都无法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用。
一.使用步骤
(1)定义配置类
@EnableAsync开始对异步任务的支持
- @Configuration
- @EnableAsync
- public class ThreadPoolTaskConfig {
-
- private static final int corePoolSize = 10; // 核心线程数(默认线程数)
- private static final int maxPoolSize = 100; // 最大线程数
- private static final int keepAliveTime = 10; // 允许线程空闲时间(单位:默认为秒)
- private static final int queueCapacity = 200; // 缓冲队列数
- private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀
-
- @Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
- public ThreadPoolTaskExecutor getAsyncExecutor(){
- ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
- executor.setCorePoolSize(corePoolSize);
- executor.setMaxPoolSize(maxPoolSize);
- executor.setQueueCapacity(queueCapacity);
- executor.setKeepAliveSeconds(keepAliveTime);
- executor.setThreadNamePrefix(threadNamePrefix);
-
- // 线程池对拒绝任务的处理策略
- executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
- // 初始化
- executor.initialize();
- return executor;
- }
- }
(2)定义service方法
@Async注解来声明一个或多个异步任务,可以加在方法或者类上,加在类上表示这整个类都是使用这个自定义线程池进行操
- @Service
- public class testAsyncService {
- Logger log = LoggerFactory.getLogger(testAsyncService.class);
-
- // 发送提醒短信 1
- @Async("taskExecutor")
- public void service1() throws InterruptedException {
- log.info("--------start-service1------------");
- Thread.sleep(5000); // 模拟耗时
- log.info("--------end-service1------------");
- }
-
- // 发送提醒短信 2
- @Async("taskExecutor")
- public void service2() throws InterruptedException {
-
- log.info("--------start-service2------------");
- Thread.sleep(2000); // 模拟耗时
- log.info("--------end-service2------------");
-
- }
- }
(3)测试
创建control类,@Autowired这个service,调用这两个方法两次,运行结果为:
--------start-service1------------
--------start-service2------------
--------end-service2------------
--------end-service1------------
可以说明我们的异步运行成功了
二、@Async失效场景和注意事项
1、异步方法使用static修饰
2、异步类没有注入ioc容器导致spring无法扫描到异步类
3、异步方法不能与异步方法在同一个类中
4、调用@Async需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
5、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
6、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。
7、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中不然不会起作用
8、使用@Async时要求是不能有返回值的不然会报错的 因为异步要求是不关心结果的