发布时间:2023-05-13 17:30
当业务需要异步处理的时候(例如异步保存操作日志),我们不能简单的通过new Thread的方式来使用,这样子性能低,重复的创建Thread和回收Thread非常的占用资源,所以我们使用Java的线程池机制,来做到线程的回收利用,线程池的介绍详见我的另一篇文章:java多线程线程池原理剖析
@Async的使用方式如下
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author zhangxing
* @date 2021/5/11
*/
@Configuration
// 使用该注解,打开SpringBoot对异步的支持
@EnableAsync
public class AsyncConfig {
private static final int CORE_POOL_SIZE = 8;
private static final int MAX_POOL_SIZE = 16;
private static final int QUEUE_CAPACITY = 200;
private static final int KEEP_ALIVE_SECONDS = 60;
private static final String THREAD_NAME_PREFIX = \"LogThreadPool-\";
@Bean(\"logThreadPoolTaskExecutor\")
public Executor logThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数量
executor.setCorePoolSize(CORE_POOL_SIZE);
// 最大线程数量
executor.setMaxPoolSize(MAX_POOL_SIZE);
// 队列中最大任务数
executor.setQueueCapacity(QUEUE_CAPACITY);
// 线程名称前缀
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
// 当达到最大线程数时如何处理新任务
// 此处不使用ThreadPoolExecutor.CallerRunsPolicy()的拒绝策略,如果异步线程池的线程不够用,则会使用将任务提交过来的线程处理,即此处的web容器的主线程,禁止该操作,并发高日志写入慢的时候可能会将主线程全部占用,此时用户无法正常访问系统
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 抛弃旧日志的拒绝策略,因为日志可以容忍丢失,所以这里选择丢失最早的没有被处理的任务,如果不能容忍丢失,还需要异步处理,请使用mq中间件或更大的等待队列
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
// 线程空闲后最大存活时间
executor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
// 初始化线程池
executor.initialize();
return executor;
}
}
public class OrderServiceImpl {
@Autowired
private LogServiceImpl logServiceImpl;
public void createOrder () {
....
// 异步保存日志
logServiceImpl.saveLog();
}
}
public class LogServiceImpl {
// 此处必须指明需要使用的线程池的beanName
@Async(\"logThreadPoolTaskExecutor\")
public void saveLog() {
// 保存日志
}
}
SimpleAsyncTaskExecutor
,该线程池本质上每来一个新任务都开启新线程,并且没有线程上线,不能起到线程复用的效果,不推荐使用CallerRunsPolicy
,那么该异步线程池中的线程不够用时,会将任务还给创建任务的线程来处理,一般正常情况会将任务还给web容器的主线程处理,会影响用户的使用性能,不建议使用【YoloV5 6.0|6.1 部署 TensorRT到torchserve】环境搭建|模型转换|engine模型部署(详细的packet文件编写方法)
#nginx学习(5)#nginx的七层负载均衡和四层负载均衡配置
详解升讯威在线客服系统前端 JavaScript 脚本加密技术(1)
SAP Fiori 应用 Adapt UI 动态显示或者隐藏的技术设计细节解析
Hive/MaxCompute SQL性能优化(一):什么是数据倾斜
python jupyter notebook运行没反应_jupyter notebook常见问题解决办法
python入门之函数结构函数的参数_Python基础知识之函数总结
MindSpore报错ValueError: For 'AvgPool' 输出形状的每一维都要大于零