CompleteFuture异步执行失败却返回成功
1、自定义线程池
@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("thread-pool-%d").build(),new ThreadPoolExecutor.CallerRunsPolicy());}}
编写三个简单的异步任务,在第三个任务执行时制造异常
public static final ThreadPoolExecutor threadPoolExecutor = ThreadPoolConfig.getThreadPoolExecutor();/*** 异步任务编排*/
@GetMapping("/asyncTaskArrange")
public ResponseData asyncTaskArrange() {try {CompletableFuture.runAsync(() -> log.info("任务1"), threadPoolExecutor).thenRunAsync(() -> log.info("任务2"), threadPoolExecutor).thenRunAsync(() -> {log.info("任务3");int i = 1 / 0;}, threadPoolExecutor).exceptionally(e -> {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());});return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");} catch (Exception e) {log.error("程序异常信息: " + e.getMessage(), e);return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());}
}
程序执行结果 控制台却打印了异常信息,异步任务自己捕获并抛出了异常信息,但是最外成决定程序执行成功失败的try-catch没有捕获到异常信息,所以返回成功。 解决办法就是让异步任务生成CompleteFuture,并调用get()方法或者join(),注意:异步任务中get()是阻塞的,使用时需要添加超时时间。
/*** 异步任务编排*/
@GetMapping("/asyncTaskArrange")
public ResponseData asyncTaskArrange() {try {CompletableFuture future = CompletableFuture.runAsync(() -> log.info("任务1"), threadPoolExecutor).thenRunAsync(() -> log.info("任务2"), threadPoolExecutor).thenRunAsync(() -> {log.info("任务3");int i = 1 / 0;}, threadPoolExecutor).exceptionally(e -> {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());});// future.get(10, TimeUnit.SECONDS);future.join();return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");} catch (Exception e) {log.error("程序异常信息: " + e.getMessage(), e);return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());}
}
再次执行程序,就能返回接口正确的执行结果
异步任务异常信息处理方法
handle
handle需要在可能发生异常的异步方法后调用,e表示上一个异步任务的异常信息,如果为null,表示执行成功,否则发现异常,需要抛出异常信息。
/*** handle处理异步异常*/@GetMapping("/asyncHandle")public ResponseData asyncHandle() {try {CompletableFuture future = CompletableFuture.runAsync(() -> log.info("任务1"), threadPoolExecutor).thenRunAsync(() -> log.info("任务2"), threadPoolExecutor).thenRunAsync(() -> {log.info("任务3");int i = 1 / 0;}, threadPoolExecutor).handle((result, e) -> {if (e != null) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());} else {return null;}});// future.get(10, TimeUnit.SECONDS);future.join();return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");} catch (Exception e) {log.error("程序异常信息: " + e.getMessage(), e);return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());}}
现在改变handle的位置,放在不会方式异常的异步任务之后,再次进行测试,依然能捕获到异常,所以handle是会捕获一整个编排的异步任务链。
/*** handle处理异步异常*/@GetMapping("/asyncHandle")public ResponseData asyncHandle() {try {CompletableFuture future = CompletableFuture.runAsync(() -> log.info("任务1"), threadPoolExecutor).thenRunAsync(() -> log.info("任务2"), threadPoolExecutor).handle((result, e) -> {if (e != null) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());} else {return null;}}).thenRunAsync(() -> {log.info("任务3");int i = 1 / 0;}, threadPoolExecutor);// future.get(10, TimeUnit.SECONDS);future.join();return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");} catch (Exception e) {log.error("程序异常信息: " + e.getMessage(), e);return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());}}
whenComplete
whenComplete任务执行完毕之后的回调方法,也是通过入参中的e来判断上一个异步任务是否存在异常。
/*** handle处理异步异常*/@GetMapping("/asyncWhenComplete")public ResponseData asyncWhenComplete() {try {CompletableFuture future = CompletableFuture.runAsync(() -> log.info("任务1"), threadPoolExecutor).thenRunAsync(() -> log.info("任务2"), threadPoolExecutor).thenRunAsync(() -> {log.info("任务3");int i = 1 / 0;}, threadPoolExecutor).whenComplete((result , e) -> {if (e != null) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());}});// future.get(10, TimeUnit.SECONDS);future.join();return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");} catch (Exception e) {log.error("程序异常信息: " + e.getMessage(), e);return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());}}
exceptionally
如果编排的异步任务执行异常会执行exceptionally,如果执行正常,会返回执行正常的结果。