CompletableFuture中completeExceptionally与obtrudeException的区别是什么?
核心差异
completeExceptionally(Throwable ex):仅当CompletableFuture处于未完成状态时,才会将其标记为异常完成,方法返回true表示设置成功。如果Future已经完成(包含正常完成、异常完成两种情况),该方法直接返回false,不会修改已有的结果,后续调用get()会返回原本的结果。obtrudeException(Throwable ex):完全忽略CompletableFuture的当前状态,无论它是未完成、正常完成还是已经异常完成,都会强制覆盖结果为传入的异常,方法无返回值,后续所有调用get()的请求都会抛出你传入的异常。
代码示例对比
场景1:Future处于未完成状态
此时两个方法效果基本一致:
// completeExceptionally测试 CompletableFuture<String> future1 = new CompletableFuture<>(); boolean setSuccess = future1.completeExceptionally(new RuntimeException("自定义异常1")); System.out.println(setSuccess); // 输出 true,设置成功 try { future1.get(); } catch (Exception e) { System.out.println(e.getCause().getMessage()); // 输出 自定义异常1 } // obtrudeException测试 CompletableFuture<String> future2 = new CompletableFuture<>(); future2.obtrudeException(new RuntimeException("自定义异常2")); try { future2.get(); } catch (Exception e) { System.out.println(e.getCause().getMessage()); // 输出 自定义异常2 }
场景2:Future已经正常完成
此时两个方法差异会非常明显:
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("业务正常返回结果"); // 调用completeExceptionally尝试修改 boolean setSuccess = completedFuture.completeExceptionally(new RuntimeException("尝试覆盖结果")); System.out.println(setSuccess); // 输出 false,设置失败 try { System.out.println(completedFuture.get()); // 输出 业务正常返回结果,原有结果未被修改 } catch (Exception e) { e.printStackTrace(); } // 调用obtrudeException强制修改 completedFuture.obtrudeException(new RuntimeException("强制覆盖为异常结果")); try { completedFuture.get(); } catch (Exception e) { System.out.println(e.getCause().getMessage()); // 输出 强制覆盖为异常结果,原有结果被覆盖 }
适用场景
- 使用
completeExceptionally:这是常规业务开发的首选方法,符合异步任务的执行逻辑,不会破坏已经完成的任务结果,线程安全。适合在异步任务执行失败时,给未完成的Future设置异常返回值,避免多线程场景下覆盖其他线程已经设置的正常结果。 - 使用
obtrudeException:仅用于特殊的错误恢复、功能测试、任务强制终止场景,比如你确认已经返回的结果是错误的,需要让所有等待该结果的调用方都拿到指定异常。该方法属于非常规操作,生产环境尽量避免使用,很容易引发预期外的逻辑异常。
内容的提问来源于stack exchange,提问作者Akhil Kooliyatt
相关产品推荐
相关产品推荐

