@Async的简单使用在我们日常的开发中,免不了要考虑使用异步、多线程等使用场景,目前使用的最多的就是自定义线程池和Spring自带的@Async异步的注解了。
@Async注解最简单的使用场景就是,异步发邮件等情况了!
首先我们需要在启动类上加启用异步注解@EnableAsync,然后在需要异步的类上加@Async注解就行了。
启动类:
@SpringBootApplication
@EnableDiscoveryClient
@EnableAsync //开启异步
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
邮件发送实现类:
@Override
@Async //将该方法异步
public BusinessResponse sendEmail(EmailReqVO emailReqVO) {
try {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(sendUserName); //设置发送邮件账号
simpleMailMessage.setTo(emailReqVO.getTos().toArray(new String[emailReqVO.getTos().size()])); //设置接收邮件的人,可以多个
simpleMailMessage.setSubject(emailReqVO.getSubject()); //设置发送邮件的主题
simpleMailMessage.setText(emailReqVO.getText()); //设置发送邮件的内容
mailSender.send(simpleMailMessage);
} catch (MailException e) {
throw new BusinessException("邮件发送失败!");
}
return BusinessResponse.ok(Boolean.TRUE);
}
以上就是最简单的使用了浪,是不是简单到都不用讲了,确实就是这么简单樂!
@Async自定义线程池自定义线程池有几种方法,就看友友们选那个了。
第一种:@SpringBootApplication
public class UserApplication{
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
@EnableAsync
@Configuration
class TaskPoolConfig {
@Bean("threadPoolTaskExecutor")
public Executor taskExecutor() {
// ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装处理。
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//队列最大长度
threadPoolTaskExecutor.setQueueCapacity(1000);
//指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;
threadPoolTaskExecutor.setCorePoolSize(10);
//指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;
threadPoolTaskExecutor.setMaxPoolSize(20);
//当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁;
threadPoolTaskExecutor.setKeepAliveSeconds(60);
//配置线程池中的线程的名称前缀
threadPoolTaskExecutor.setThreadNamePrefix("thread-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolTaskExecutor;
}
}
}
如何使用:
@Override
@Async("threadPoolTaskExecutor") //使用threadPoolTaskExecutor线程池来进行异步操作
public BusinessResponse sendEmail(EmailReqVO emailReqVO) {
try {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(sendUserName); //设置发送邮件账号
simpleMailMessage.setTo(emailReqVO.getTos().toArray(new String[emailReqVO.getTos().size()])); //设置接收邮件的人,可以多个
simpleMailMessage.setSubject(emailReqVO.getSubject()); //设置发送邮件的主题
simpleMailMessage.setText(emailReqVO.getText()); //设置发送邮件的内容
mailSender.send(simpleMailMessage);
} catch (MailException e) {
throw new BusinessException("邮件发送失败!");
}
return BusinessResponse.ok(Boolean.TRUE);
}
第二种:
第二种和第一种其实也差不多只是将线程池配置给了Spring的Async了,这种的使用就帮你解决了异步的方法上还要写@Async("threadPoolTaskExecutor")这么多了,用了之后就可以这样写了@Async,是不是很方便呢?
@Configuration
@EnableAsync
public class AsyncTaskConfigurer implements AsyncConfigurer {
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final int Queue_Capacity = 1000;
private static final String Thread_Name_Prefix = "async-service-";
@Override
public Executor getAsyncExecutor() {
//ThreadPoolTaskExecutor是spring core包中的,而ThreadPoolExecutor是JDK中的JUC。
// ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装处理。
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//队列最大长度
threadPoolTaskExecutor.setQueueCapacity(Queue_Capacity);
//指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;
threadPoolTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
//指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;
threadPoolTaskExecutor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
//当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁;
threadPoolTaskExecutor.setKeepAliveSeconds(KEEP_ALIVE);
//配置线程池中的线程的名称前缀
threadPoolTaskExecutor.setThreadNamePrefix(Thread_Name_Prefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
}
}
第三种:
第三种就是使用了Spring自己的默认线程池了
默认使用Spring创建ThreadPoolTaskExecutor
默认核心线程数:8
最大线程数:Integet.MAX_VALUE
队列使用LinkedBlockingQueue
容量是:Integet.MAX_VALUE
空闲线程保留时间:60s
线程池拒绝策略:AbortPolicy
不过我们也可以自己设置默认的线程池,在yml文件下添加如下配置:
spring:
task:
execution:
pool:
max-size: 10
core-size: 2
keep-alive: 3s
queue-capacity: 1000
thread-name-prefix: name
以上就是@Async线程池的使用啦,看到这可不可以点个收藏呢!
问题以及解决办法: Spring boot 注解@Async不生效- @SpringBootApplication启动类当中没有添加@EnableAsync注解。
- 异步方法使用注解@Async的返回值只能为void或者Future。
- 没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器管理。
@Slf4j @Service public class OrderServiceTestImpl extends ServiceImpl解决方法:implements OrderServiceTest { public void getOrderList(){ asyncGetOrderList(); } @Async // 不会生效 public void asyncGetOrderList(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } log.info("异步测试"); } }
- 注解的方法必须是public方法。
- 方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的。
- 如果需要从类的内部调用,需要先获取其代理类。
将方法抽出来就可以啦!
public void getOrderList(){
OrderServiceTestImpl bean = SpringUtil.getBean(OrderServiceTestImpl.class);
bean.asyncGetOrderList();
}
再线程套线程的情况这样也可以解决哦,或者抽到另外一个实现类去也是可以的呢!
好啦,本章结束。期待下次见面!!!



