来,用时15分钟,手敲一段代码(含伪代码)。这是我们系统其中一次迭代的开发内容:每次调用银行接口查询订单支付状态时,如果对方返回404-订单不存在,并且如果订单是在5min前创建的,那么,就触发重新下发,要求每笔订单只可重发一次。
你先读一下。
/**
* 银行查单服务类
*/
@Service
public class BankOrderQueryService {
@Autowired
private OrderRepeatPayService orderRepeatPayService;
public void queryBank(BankOrder order) {
// 调用银行接口查询支付结果
String responseMsg = ...
BankQueryResult queryResult = JSON.parseObject(responseMsg, BankQueryResult.class);
switch ( queryResult.state ) {
case 成功:
// 支付成功的处理
...
break;
case 失败:
// 支付失败的处理
...
break;
case 404:
// 支付单不存在, 触发重发逻辑
...
orderRepeatPayService.repeatPay(order);
break;
default:
//
...
break;
}
}
}
import org.springframework.scheduling.annotation.Async;
/**
* 订单重发服务类
*/
@Slf4j
@Service
public class OrderRepeatPayService {
/**
* 注入订单下发服务类
*/
@Autowired
private BankOrderPayService bankOrderPayService;
/**
* 订单重发(只重发一次)
*/
@Async
public void repeatPay(BankOrder order) {
if (!canRepeatPay(order)){
log.info("订单不满足重发条件,中止");
return;
}
//组装参数,调用下发服务,实现再次下发
bankOrderPayService.pay(order);
}
private static boolean canRepeatPay(BankOrder order){
if(order.createTime <= (当前时间-5min)
&& redisUtil.setnx("orderRepeatPay:"+order.orderId, "Y", HOUR.toMillis(24))){
return true;
}
return false;
}
}
我在review上面代码时,其中,注意到了@Async注解。那么,上面代码有什么不足呢?
主线程方法 BankOrderQueryService#queryBank 每当满足条件state=404时,都会调用标记了@Async的异步方法 OrderRepeatPayService#repeatPay。 OrderRepeatPayService#repeatPay里的订单重发的逻辑,并不总是会触发。上面文章开头描述了,每笔订单只可重发一次。 所以,不足就显现出来了————JVM会不停地创建线程然后很快释放。如果交易量大,可能会导致线程无法创建(jvm:unable to create new native thread)。
所以,我明确告诉小组成员:该用异步的时候再用异步。
那么,这段代码怎么优化呢? 想必你已经有了答案。 我跟上图这哥们一个毛病,就容我碎碎念再一下吧。
/**
* 银行查单服务类
*/
@Service
public class BankOrderQueryService {
@Autowired
private OrderRepeatPayService orderRepeatPayService;
public void queryBank(BankOrder order) {
// 调用银行接口查询支付结果
String responseMsg = ...
BankQueryResult queryResult = JSON.parseObject(responseMsg, BankQueryResult.class);
switch ( queryResult.state ) {
case 成功:
// 支付成功的处理
...
break;
case 失败:
// 支付失败的处理
...
break;
case 404:
// 支付单不存在, 触发重发逻辑
...
orderRepeatPayService.repeatPay(order);
break;
default:
//
...
break;
}
}
}
// import org.springframework.scheduling.annotation.Async;
/**
* 订单重发服务类
*/
@Slf4j
@Service
public class OrderRepeatPayService {
/**
* 注入订单下发服务类
*/
@Autowired
private BankOrderPayService bankOrderPayService;
/**
* 订单重发(只重发一次)
*/
public void repeatPay(BankOrder order) {
if (!canRepeatPay(order)){
log.info("订单不满足重发条件,中止");
return;
}
//组装参数,调用下发服务,实现再次下发(异步处理)
ThreadPoolUtil.getThreadPoolExecutor().execute(()->
bankOrderPayService.pay(order));
}
private static boolean canRepeatPay(BankOrder order){
if(order.createTime <= (当前时间-5min)
&& redisUtil.setnx("orderRepeatPay:"+order.orderId, "Y", HOUR.toMillis(24))){
return true;
}
return false;
}
}