CompletableFuture 异步关于异常的坑

40 篇文章 0 订阅

https://juejin.cn/post/7324933059819962394?share_token=AF8858A1-B78E-46DB-A93A-3155AA6D96DD

直接上代码!首先定义一个线程池的配置类!

 

scss

复制代码

@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());     } }

程序存在异常,却返回成功

写一个存在异常的程序,让其异步执行

 

java

复制代码

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());     } }

结果:接口返回成功,控制台没有打印错误信息。

图片

异步调用join()

 

csharp

复制代码

// 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()是阻塞的,在使用时要设置超时时间。

 

csharp

复制代码

// 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()

 

csharp

复制代码

// 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()

 

csharp

复制代码

// 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()

 

csharp

复制代码

// 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()

 

vbnet

复制代码

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()处理。

作者:程序员蜗牛
链接:https://juejin.cn/post/7324933059819962394
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Micrle_007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值