主题
面试速答(先看这里)
**一句话结论:**我的项目中,有这样一个场景,我们要发起一个用户主动还款之后,需要把在途的扣款单全部暂停,但是因为用户选择还款单据可能比较多,而且暂停是调用外部资金打款系统的接口实现的,这个地方如果一条一条执行就很慢,但是如果起多线程执行的话,我就没办法知道他们每一个暂定的返回结果。
60秒标准回答:
我的项目中,有这样一个场景,我们要发起一个用户主动还款之后,需要把在途的扣款单全部暂停,但是因为用户选择还款单据可能比较多,而且暂停是调用外部资金打款系统的接口实现的,这个地方如果一条一条执行就很慢,但是如果起多线程执行的话,我就没办法知道他们每一个暂定的返回结果
我想可以实现一个这样的功能:多线程去执行暂停动作,如果都成功了,那么就推进我的主动扣款后续流程,如果暂停有任何一个接口调用失败了,那么先不推进后续流程,等下次重试
为了实现这个功能,我了解到CompletableFuture,他是Java 8中引入的一个新特性,它提供了一种简单的方法来实现异步编程和任务组合
**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点
回答主线:
- **要点1:**我想可以实现一个这样的功能:多线程去执行暂停动作,如果都成功了,那么就推进我的主动扣款后续流程,如果暂停有任何一个接口调用失败了,那么先不推进后续流程,等下次重试。
- **要点2:**为了实现这个功能,我了解到CompletableFuture,他是Java 8中引入的一个新特性,它提供了一种简单的方法来实现异步编程和任务组合。
- **要点3:**他的多线程编排的能力刚好可以用在我这个场景中,而且他底层是基于ForkJoinPool实现的,所以他的性能也比较高效,所以最终我选择了这个方案。
- **要点4:**在用了CompletableFuture做编排之前,原来50笔订单的暂停扣款,需要大概10s左右,但是用了CompletableFuture之后,50笔订单的暂停扣款只需要1秒钟左右。
**记忆锚点:**CompletableFuture → ForkJoinPool → 部资金打款系统的接口 → 等下次重试 → 他的多线程 → Java
关键取舍:
- 他的多线程编排的能力刚好可以用在我这个场景中,而且他底层是基于ForkJoinPool实现的,所以他的性能也比较高效,所以最终我选择了这个方案。
易错提醒:
- 我想可以实现一个这样的功能:多线程去执行暂停动作,如果都成功了,那么就推进我的主动扣款后续流程,如果暂停有任何一个接口调用失败了,那么先不推进后续流程,等下次重试。
加分表达:
- 我的项目中,有这样一个场景,我们要发起一个用户主动还款之后,需要把在途的扣款单全部暂停,但是因为用户选择还款单据可能比较多,而且暂停是调用外部资金打款系统的接口实现的,这个地方如果一条一条执行就很慢,但是如果起多线程执行的话,我就没办法知道他们每一个暂定的返回结果。
追问准备:
- 围绕「CompletableFuture」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「ForkJoinPool」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「部资金打款系统的接口」:底层原理是什么?使用时有哪些边界和常见坑?
- 如果线上出现异常,你会如何定位、验证并规避?
背景
我的项目中,有这样一个场景,我们要发起一个用户主动还款之后,需要把在途的扣款单全部暂停,但是因为用户选择还款单据可能比较多,而且暂停是调用外部资金打款系统的接口实现的,这个地方如果一条一条执行就很慢,但是如果起多线程执行的话,我就没办法知道他们每一个暂定的返回结果。
我想可以实现一个这样的功能:多线程去执行暂停动作,如果都成功了,那么就推进我的主动扣款后续流程,如果暂停有任何一个接口调用失败了,那么先不推进后续流程,等下次重试。
技术选型
为了实现这个功能,我了解到CompletableFuture,他是Java 8中引入的一个新特性,它提供了一种简单的方法来实现异步编程和任务组合。
他的多线程编排的能力刚好可以用在我这个场景中,而且他底层是基于ForkJoinPool实现的,所以他的性能也比较高效,所以最终我选择了这个方案。
具体实现
java
//异步暂停扣款
CompletableFuture<Void> allFutures = CompletableFuture.allOf(noticeDetails.stream()
.map(detail -> CompletableFuture.supplyAsync(() -> {
pause(detail);
return null;
})).toArray(CompletableFuture[]::new));
//所有暂停扣款成功后,更新代还通知单
allFutures.whenComplete((v, e) -> {
if (e == null) {
//执行后续的还款操作
//...
//...
} else {
log.error("notice failed", e);
}
});得到结果
在用了CompletableFuture做编排之前,原来50笔订单的暂停扣款,需要大概10s左右,但是用了CompletableFuture之后,50笔订单的暂停扣款只需要1秒钟左右。
学习资料
📄 ✅CompletableFuture的底层是如何实现的?
打开文档:✅CompletableFuture的底层是如何实现的?