直接上代码!首先定义一个线程池的配置类!
@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());
????}
}
写一个存在异常的程序,让其异步执行
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方法获取异常信息:?将异步线程中发生的异常信息抛到主线程,?这样异常可被主线程捕获
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方法获取异常信息:?将异步线程中发生的异常信息抛到主线程,?这样异常可被主线程捕获
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());
}
结果:接口返回成功,控制台打印异常信息。
图片
//?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获取异常信息:?异常是存在于异步当中的,?不能被主线程捕获
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获取异常信息:?异常是存在于异步当中的,?不能被主线程捕获
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());
}
结果:结果返回成功,控制台打印异步线程异常信息,主线程没有打印异常信息
图片
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()。
在使用异步CompletableFuture时,无论是否有返回值都要调用get()/join()方法,避免程序执行报错了,仍然返回成功。
如果在程序报错时需要对上一个异步任务结果做其他操作,可以调用whenComplete()
、handle()
处理,如果只是对异常做处理,不涉及对上一个异步任务结果的情况,调用exceptionally()
处理。
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。
关注公众号:woniuxgg,在公众号中回复:笔记??就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!