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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。