题目
用户有多种支付方式(余额、红包、优惠券,代金券等),假如每种支付方式需要通过实时调用远程服务获取可用性。在外部资源环境不变情况下,请设计程序以最短响应时间获得尽可能多的可用支付方式列表。
假定支付方式可用性咨询服务接口定义:PaymentRemoteSerivce
接口方法:ConsultResult isEnabled(String paymentType)
;
public class ConsultResult { public ConsultResult (boolean isEnable,String errorCode){ this.isEnable = isEnable; this.errorCode= errorCode; } /** 咨询结果是否可用*/ private boolean isEnable; /** 错误码 */ private String errorCode; public boolean getIsEnable(){ return isEnable; } public String getErrorCode(){ return errorCode; } }
题目要求:
「尽可能展示你的编码能力(Java语法、编码风格等),java语言肯定比伪代码得分高」
看到这里的小伙伴的可以思考一会哦
解题
这道题,说难真的不难。
拿到题目之后,我们首先分析一下,切记直接上手写。
在我们的分析过程,梳理设计要点,并且可以向面试官确认这些设计点是否正确,最后我们才开始真正写代码。
我们来看下这道题的关键词:
- 最短
- 实时
- 远程调用
- 另外需要考虑高并发
结合这几个关键点,第一个很容易想到的方案,遍历查询所有支付方式的可用性,然后返回。
「这种做法响应时间就是多次调用远程服务的总和。」
不过显然不符合设计要求。
第二种,我们可以想象一下,支付方式可用性在一段时间内不怎么会变化的,所以我们可以在第一种的方式基础上,优化一下,增加缓存保存之前的调用结果。
「这种方案只在前面查询的时候耗时较长,后面查询直接走缓存,速度较快。」
但是引入缓存有一个弊端,就是某一支付方式如果突然不可用了或者不可用支付突然变成可用了,那在缓存还未失效的这段时间,将会获取不准确的结果。
所以我们需要引入刷新进制,定时查询支付方式可用性,然后更新缓存。
当然如果在定时任务还未刷新的间隔,支付方式突然不可用,依然还是会存这个问题。
这个问题,第一种解决方案,加快定时任务刷新频率。
第二种方案,需要其他服务配合。如果某一支付方式突然从可用变成不可用,或者不可用变成可用了,这种情况发送相应的消息,这边服务受到消息及时更新缓存结果。
第二种设计方案,我们已经在一定程度上优化设计,不过还是存在一些问题。
主要问题还是在于第一次查询遍历查询所有支付方式的可用性,速度较慢。
那这个问题,我们其实就可以引入多线程查询,这样的话,响应时间最大值等于单一支付最长调用那一次。
结合以上的分析,我们代码可以如下:
多线程查询代码:
缓存定时刷新的代码如下:
考虑接口会被高并发调用,在缓存为空的时候,可能会有多个线程并发调用 asyncQueryALLPaymentTypes 查询所有的支付方式的结果。
但是实际上这里只需要一个线程查询即可,其他线程等待结果就可以。
所以接口使用双重查询锁(DCL)的方式,同时只会有一个线程去查询所有支付方式。
上述 DCL 的方式只是解决同一个应用内多线程的问题,但是多个应用间被并发调用,还是可能会多线程去查询所有支付可用性。
假设现有 10 个应用,缓存为空,极端情况下,10 个应用都使用多线程去查询支付方式可用性。
假设现有 5 个支付方式,短时间内发起 10 *5=50 次调用,这种调用量还是很少,完全可以接受。
好了,今天分享就到这里了~