点击上方“Java基基”,选择“设为星标”
做积极的人,而不是积极废人!
每天 14:00 更新文章,每天掉亿点点头发...
源码精品专栏
来源:blog.csdn.net/weixin_43356538
自定义线程池
@Configuration
public class ThreadPoolConfig {
public static ThreadPoolExecutor getThreadPoolExecutor() {
int availableProcessors = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(
availableProcessors,
availableProcessors,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(9999),
new ThreadFactoryBuilder().setNameFormat("custom-thread-pool-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
}
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro
视频教程:https://doc.iocoder.cn/video/
程序存在异常,却返回成功
写一个存在异常的程序,让其异步执行
public static final ThreadPoolExecutor CUSTOM_THREAD_POOL = ThreadPoolConfig.getThreadPoolExecutor();
/**
* 异步执行异常测试
*/
@ApiOperation(value = "异步执行异常测试", code = 800)
@GetMapping("/asyncException")
public ResponseData<Object> asyncException() {
try {
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL);
} catch (Exception e) {
log.error("异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");
} catch (Exception e) {
return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());
}
}
结果:接口返回成功,控制台没有打印错误信息。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud
视频教程:https://doc.iocoder.cn/video/
异步调用join()
// join方法获取异常信息: 将异步线程中发生的异常信息抛到主线程, 这样异常可被主线程捕获
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL).join();
} catch (Exception e) {
log.error("外层异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
结果:接口返回失败,控制台打印异常日志。
异步调用get()
异步方法中get()是阻塞的,在使用时要设置超时时间。
// get方法获取异常信息: 将异步线程中发生的异常信息抛到主线程, 这样异常可被主线程捕获
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL).get(2, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("外层异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
结果:接口返回成功,控制台打印异常信息。
异步调用exception()
// exceptionally获取异常信息: 异常是存在于异步当中的, 不能被主线程捕获
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL)
.exceptionally(e -> {
log.error("异步运行异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
});
} catch (Exception e) {
log.error("异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
结果:接口返回成功,控制台打印异步线程异常日志,主线程没有打印异常日志
异步调用whenComplete()
// whenComplete获取异常信息: 异常是存在于异步当中的, 不能被主线程捕获
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL)
.whenComplete((r, e) -> {
if (e != null) {
log.error("异步执行异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
});
} catch (Exception e) {
log.error("异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
结果:结果返回成功,控制台打印异步线程异常信息,主线程没有打印异常信息
异步调用handle()
// handle获取异常信息: 异常是存在于异步当中的, 不能被主线程捕获
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL)
.handle((r, e) -> {
if (e != null) {
log.error("异步执行异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
return null;
});
} catch (Exception e) {
log.error("异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
结果:结果返回成功,控制台打印异步线程异常信息,主线程没有打印异常信息
程序发生异常时需要做处理,可以调用get()/join()
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL)
.exceptionally(e -> {
log.error("异步执行异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}).join();
} catch (Exception e) {
log.error("异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
try {
CompletableFuture.runAsync(() -> {
int i = 1 / 0;
}, CUSTOM_THREAD_POOL)
.exceptionally(e -> {
log.error("异步执行异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}).get(2, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("异常信息: " + e.getMessage(), e);
throw new BusinessException(e.getMessage());
}
程序发生异常时不做处理直接报错,直接调用get()/join()
直接的异步方法后调用get()/join()。
总结
在使用异步CompletableFuture时,无论是否有返回值都要调用get()/join()方法,避免程序执行报错了,仍然返回成功。如果在程序报错时需要对上一个异步任务结果做其他操作,可以调用whenComplete()
、handle()
处理,如果只是对异常做处理,不涉及对上一个异步任务结果的情况,调用exceptionally()
处理。
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)