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项目中接口对接,有反馈接口(也就是我们接收到请求,需要立即响应,并且还要有一个接口推送给他们其他计算结果),推送过程耗时.或者说两个接口不能是同时返回,有先后顺序. 这时我想 ...
随机推荐
- Tomcat 部署多个项目出现错误
有时,我们会遇到部署同样项目可是不同版本号来回切换的问题.可是有时就是莫名奇异的会起不来. 也没太多时间去解决这些问题,所以就又一次把纯净版的Tomcat部署进去就能够了. 我想非常有可能就是Tomc ...
- 【Android】解析Paint类中Xfermode的使用
Paint类提供了setXfermode(Xfermode xfermode)方法,Xfermode指明了原图像和目标图像的结合方式.谈到Xfermode就不得不谈它的派生类PorterDuffXfe ...
- Android 隐藏系统状态栏
通常的做法是这样的: private static boolean isStatusbarVisible(Activity activity) { int uiOptions = activity.g ...
- crawler_exa3
优化中... #! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma ''' v1.0: 由于网站结构存在变更的可能性,一旦爬虫爬 ...
- ssh连接服务器失败解决记录
故障:db2inst1用户无法通过ssh连接数据库服务器. 但是root用户可以连接,连接后su – db2inst1用户报错: su: cannot set user id: Resource te ...
- iOS 实现单个页面支持横竖屏,其他页面只能竖屏
最近在自己的项目里面 有需要做一个需求 : app中某一个页面支持横竖屏, 而其他页面只能竖屏. 1 2 实现方法如下: 1 首先需要Xcode中选中支持的屏幕方向 2 Appdelegate中 . ...
- 【iCore4 双核心板_ARM】例程三十一:HTTP_IAP_FPGA实验——更新升级FPGA
实验现象: 核心代码: int main(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOI_CLK_ENABLE(); __HAL_R ...
- Android Studio报错Error:Failed to open zip file. Gradle's dependency cache may be corrupt
Android Studio导入项目后,Gradle编译失败,报错如下. Error:Failed to open zip file. Gradle's dependency cache may be ...
- dockerd启动配置_修改IP和systemd管理
docker采用CS架构,dockerd是管理后台进程,默认的配置文件为/etc/docker/daemon.json(--config-file可以指定非默认位置). 一个完整的daemon.jso ...
- 使用git创建与合并分支
一.概述 学会使用git命令对项目进行创建分支,并在创建结束后合并到主分支上. 问:为什么要创建分支? 答:在原来的分支上创建一个自己的分支进行开发,在开发完毕后一次性合并到原先的分支,这样既保证安全 ...