springboot+@async异步线程池的配置及应用
示例:
1、 配置
@EnableAsync
@Configuration
public class TaskExecutorConfiguration {
@Autowired
private TaskExecutorProperties taskExecutorProperties;
@Bean
public Executor routeGen() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(taskExecutorProperties.getCorePoolSize());
executor.setQueueCapacity(taskExecutorProperties.getQueueCapacity());
executor.setMaxPoolSize(taskExecutorProperties.getMaxPoolSize());
executor.setKeepAliveSeconds(taskExecutorProperties.getKeepAliveSeconds());
executor.setThreadNamePrefix("gen-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
executor.initialize();
return executor;
}}
2、 运用(作用于方法上)
@Async("routeGen") public Future<Result<String>> genRouteByCategory(RouteGenDTO routeGenDTO, List<String> cityList, String category){}
3、 异常处理及日志记录
public Result<String> genRouteByShard(RouteGenDTO routeGenDTO) throws RouteGenException {
// 根据分片获取城市
Result<List<String>> cityResult = cityService.queryAllCity();
if (cityResult == null || !cityResult.isSuccess()) {
String errorMsg = cityResult == null ? "查询城市没有返回结果" : cityResult.getMsg();
// 记录查询城市日志
logQueryCityByShard(RouteJobTypeEnum.ROUTE_GEN, routeGenDTO, null, errorMsg);
return Result.ofFail(ErrorEnum.QUERY_ERROR.getCode(), errorMsg);
}
List<String> cityList = cityResult.getData();
if (CollectionUtils.isEmpty(cityList)) {
String errorMsg = "没有查询到城市,无需生成路线";
// 记录查询城市日志
logQueryCityByShard(RouteJobTypeEnum.ROUTE_GEN, routeGenDTO, null, errorMsg);
return Result.ofSuccessMsg(errorMsg);
}
// 记录查询城市日志
logQueryCityByShard(RouteJobTypeEnum.ROUTE_GEN, routeGenDTO, JSON.toJSONString(cityList), null);
Map<String, Future<Result<String>>> categoryFutureMap = new ConcurrentHashMap<>();
// 禁用的类别列表
List<String> disableCategoryList = null;
String disableCategory = genProperties.getDisableCategory();
if (StringUtils.isNotBlank(disableCategory)) {
String[] disableCategoryArr = disableCategory.split(",");
disableCategoryList = Stream.of(disableCategoryArr).collect(Collectors.toList());
}
// 根据类别生成路线
// 每个类别一个线程
for (RouteCategoryEnum routeCategory : RouteCategoryEnum.values()) {
// 跳过禁用的类别
if (CollectionUtils.isNotEmpty(disableCategoryList) && disableCategoryList.contains(routeCategory.getType())) {
// 记录生成日志
logGenRouteByCategory(RouteJobTypeEnum.ROUTE_GEN, routeGenDTO, routeCategory.getType(), routeCategory.getType() + "类别被禁用,无需生成");
continue;
}
// 根据城市和类别生成路线
Future<Result<String>> categoryFuture = routeGenService.genRouteByCategory(routeGenDTO, cityList, routeCategory.getType());
categoryFutureMap.put(routeCategory.getType(), categoryFuture);
}
String lastErrorMsg = null;
for (Map.Entry<String, Future<Result<String>>> entry : categoryFutureMap.entrySet()) {
String errorMsg = null;
String category = entry.getKey();
Future<Result<String>> futureResult = entry.getValue();
if (futureResult != null) {
try {
if (futureResult.isCancelled()) {
errorMsg = "线程被取消";
log.error("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 处理失败,错误描述:{}",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), errorMsg);
continue;
}
Result<String> result = futureResult.get(CommonConfConstants.FUTURE_CATEGORY_WAIT_TIME, TimeUnit.SECONDS);
if (result == null || !result.isSuccess()) {
errorMsg = result == null ? category + "没有返回处理结果" : result.getMsg();
log.error("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 处理失败,错误描述:{}",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), errorMsg);
} else {
log.info("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 生成成功",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), result);
}
} catch (TimeoutException e) {
errorMsg = category + "生成路线 线程处理超时:" + e.getMessage();
log.error("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 线程处理超时",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), e);
} catch (InterruptedException e) {
errorMsg = category + "生成路线 线程中断异常:" + e.getMessage();
log.error("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 线程中断异常",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), e);
} catch (ExecutionException e) {
errorMsg = category + "生成路线 线程执行异常:" + e.getMessage();
log.error("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 线程执行异常",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), e);
}
} else {
errorMsg = category + "生成路线 线程返回结果为null";
log.error("分片项{} 分片总数{} 生成 {} 路线 任务开始时间:{} 处理失败,错误描述:{}",
routeGenDTO.getShardItem(), routeGenDTO.getShardTotal(), category, routeGenDTO.getStartTime(), errorMsg);
}
// 记录生成日志
logGenRouteByCategory(RouteJobTypeEnum.ROUTE_GEN, routeGenDTO, category, errorMsg);
if (StringUtils.isNotBlank(errorMsg)) {
lastErrorMsg = errorMsg;
}
}
if (StringUtils.isNotBlank(lastErrorMsg)) {
return Result.ofFail(ErrorEnum.GEN_ROUTE_FAILURE.getCode(), lastErrorMsg);
}
return Result.ofSuccess("路线生成成功");
}
private void logQueryCityByShard(RouteJobTypeEnum routeJobTypeEnum, RouteGenDTO routeGenDTO, String cityJson, String errorMsg) { String logFormat; String logMsg; if (StringUtils.isBlank(errorMsg)) { logFormat = "查询城市成功,城市信息:%s"; logMsg = String.format(logFormat, cityJson); } else { logMsg = errorMsg; }
String operationObject = routeJobTypeEnum.getType() + "_job_" + routeGenDTO.getShardItem() + "_" + TimeUtil.dateTimeToStr(routeGenDTO.getStartTime(), DateFormatConstants.DATE_TIME_COMPACT_FORMAT);
LogInfoDTO logInfoDTO = new LogInfoDTO(); logInfoDTO.setBusinessName(routeJobTypeEnum.getDesc()); logInfoDTO.setOperationName("根据分片查询城市"); logInfoDTO.setOperationObject(operationObject); logInfoDTO.setOperationDesc(logMsg); LogUtil.log(logInfoDTO);}
springboot+@async异步线程池的配置及应用的更多相关文章
- SpringBoot使用异步线程池实现生产环境批量数据推送
前言 SpringBoot使用异步线程池: 1.编写线程池配置类,自定义一个线程池: 2.定义一个异步服务: 3.使用@Async注解指向定义的线程池: 这里以我工作中使用过的一个案例来做描述,我所在 ...
- spring boot:使用async异步线程池发送注册邮件(spring boot 2.3.1)
一,为什么要使用async异步线程池? 1,在生产环境中,有一些需要延时处理的业务场景: 例如:发送电子邮件, 给手机发短信验证码 大数据量的查询统计 远程抓取数据等 这些场景占用时间较长,而用户又没 ...
- Spring Boot系列二 Spring @Async异步线程池用法总结
1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent.Executor Spring 已经实现的异常线程池: 1. SimpleAsyncT ...
- Springboot的异步线程池
1:定义线程池 @EnableAsync @Configuration class TaskPoolConfig { @Bean("taskExecutor") public Ex ...
- springBoot服务整合线程池ThreadPoolTaskExecutor与@Async详解使用
ThreadPoolExecutor:=======这个是java自己实现的线程池执行类,基本上创建线程池都是通过这个类进行的创建.ThreadPoolTaskExecutor:========这个是 ...
- Spring Boot中使用@Async的时候,千万别忘了线程池的配置!
上一篇我们介绍了如何使用@Async注解来创建异步任务,我可以用这种方法来实现一些并发操作,以加速任务的执行效率.但是,如果只是如前文那样直接简单的创建来使用,可能还是会碰到一些问题.存在有什么问题呢 ...
- springboot(十九)-线程池的使用
我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行. 话不多说,编码开始: 1.创建spri ...
- 使用C++11实现一个半同步半异步线程池
前言 C++11之前我们使用线程需要系统提供API.posix线程库或者使用boost提供的线程库,C++11后就加入了跨平台的线程类std::thread,线程同步相关类std::mutex.std ...
- 记录ThreadPoolTaskExecutor线程池的在项目中的实际应用,讲解一下线程池的配置和参数理解。
前言:最近项目中与融360项目中接口对接,有反馈接口(也就是我们接收到请求,需要立即响应,并且还要有一个接口推送给他们其他计算结果),推送过程耗时.或者说两个接口不能是同时返回,有先后顺序. 这时我想 ...
随机推荐
- 【jquery采坑】Ajax配合form的submit提交(微擎表单提交,ajax验证,submit提交)
1.采坑:实现form的submit提交,在提交之前,进行ajax的不同校验,然后onsubmit=return check(),进行提交 1/1 目的:可以实现以 from的submit提交,然后还 ...
- JDBC告警系列(一)The server time zone value 'ÖÐ' is unrecognized or represents more than one time zone.
一.现象 java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents ...
- OpenCV自带dnn的Example研究(3)— object_detection
这个博客系列,简单来说,今天我们就是要研究 https://docs.opencv.org/master/examples.html下的 6个文件,看看在最新的OpenCV中,它们是如何发挥作用的. ...
- [svc]证书学习索引
数字证书基础知识 对称加密/非对称加密细枝末节 openssl对称非对称加密实战 使用OpenSSL实现CA证书的搭建过程 通过openssl生成证书 HTTPS证书生成原理和部署细节 证书各个字段的 ...
- mac安装MySQL-Python报错
报错内容主要是: EnvironmentError: mysql_config not found Command "python setup.py egg_info" faile ...
- 【神经网络】Dependency Parsing的两种解决方案
一.Transition-based的依存解析方法 解析过程:首先设计一系列action, 其就是有方向带类型的边,接着从左向右依次解析句子中的每一个词,解析词的同时通过选择某一个action开始增量 ...
- python实现类似于Matlab中的magic函数
参考这篇文章的代码封装了一个类似Matlab中的magic函数,用来生成魔方矩阵. #!/usr/bin/env python # -*- coding: utf-8 -*- import numpy ...
- dom4j 简单使用
1,需要用到dom4j的jar包.为了打开xml方便,设计一个简单的封装类. package cn.com.gtmc.glaf2.util; import java.io.File; import j ...
- [转]git commit --amend用法
适用场景: 比方说,你的代码已经提交到git库,leader审核的时候发现有个Java文件代码有点问题,于是让你修改,通常有2种方法: 方法1:leader 将你提交的所有代码 abandon掉,然后 ...
- centos7修改系统时间、时区
直接用下面命令直接更换时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime