在我们日常的开发中,免不了要考虑使用异步、多线程等使用场景,目前使用的最多的就是自定义线程池和Spring自带的@Async异步的注解了。
@Async
注解最简单的使用场景就是,异步发邮件等情况了!
首先我们需要在启动类上加启用异步注解@EnableAsync
,然后在需要异步的类上加@Async
注解就行了。
启动类:
@SpringBootApplication
@EnableDiscoveryClient
@EnableAsync //开启异步
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
邮件发送实现类:
/**
* 发送普通邮件
*
* @param emailReqVO
* @return
*/
@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);
}
以上就是最简单的使用了浪,是不是简单到都不用讲了,确实就是这么简单樂!
自定义线程池有几种方法,就看友友们选那个了。
@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;
}
}
}
/**
* 发送普通邮件
*
* @param emailReqVO
* @return
*/
@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 {
/**
* 根据cpu的数量动态的配置核心线程数和最大线程数
*/
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
/**
* 核心线程数 = CPU核心数 + 1
*/
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
/**
* 线程池最大线程数 = CPU核心数 * 2 + 1
*/
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
/**
* 非核心线程闲置时超时1s
*/
private static final int KEEP_ALIVE = 1;
/**
* 队列最大长度 200
*/
private static final int Queue_Capacity = 1000;
/**
* 线程的名称前缀
*/
private static final String Thread_Name_Prefix = "async-service-";
/**
* The {@link Executor} instance to be used when processing async
* method invocations.
*/
@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;
}
/**
* The {@link AsyncUncaughtExceptionHandler} instance to be used
* when an exception is thrown during an asynchronous method execution
* with {@code void} return type.
*/
@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线程池的使用啦,看到这可不可以点个收藏呢!
@Slf4j
@Service
public class OrderServiceTestImpl extends ServiceImpl<OrderDao, OrderDO> implements OrderServiceTest {
public void getOrderList(){
asyncGetOrderList();
}
@Async // 不会生效
public void asyncGetOrderList(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("异步测试");
}
}
public void getOrderList(){
OrderServiceTestImpl bean = SpringUtil.getBean(OrderServiceTestImpl.class);
bean.asyncGetOrderList();
}
再线程套线程的情况这样也可以解决哦,或者抽到另外一个实现类去也是可以的呢!
好啦,本章结束。期待下次见面!!!