微信支付V3 消费后轮询支付结果的方案
1.场景
2.线程池选择
ScheduledExecutorService是延时执行的线程池,他可以用来代替timer定时器。 scheduleAtFixedRate()方法:
//循环执行任务,第一次执行时延时5秒后执行,然后第二次开始每间隔10秒执行一次,最后一个参数是时间单位 service.scheduleAtFixedRate(Runnable, 5, 10, TimeUnit.SECONDS);
大家有兴趣的可以去针对性的了了解下ScheduledExecutorService的使用,这里就不一一讲了;
3.核心线程数配置
- 轮询的时候线程经常需要挂起, 消耗的是cpu的资源, 上下文切换时间, 也就是说我们这个程序属于cpu密集型;
- 程序订单表记录的查询是根据唯一索引去查的, IO次数很少, 所以在IO上花费的时间并不多;
- 程序并发上比较稳定, 正常不会存在短时间内访问量激增的情况;
- 通过分析, 我们确定了目前的场景是: 并发不高, 执行时间长(这里的执行时间是线程挂起时间,所以消耗的是cpu的资源), 属于cpu密集型;
- 最后我们根据分析的场景把线程池的线程数设置为cpu核数+1, 线程不开太多, 减少线程上下文切换时间;
关于什么是IO密集型和CPU密集型,大家可以看下这篇文章: https://blog..net/weixin_40151613/article/details/81835974
4.代码示例
//获取当前机器的核数 public static final int cpuNum = Runtime.getRuntime().availableProcessors(); //轮询 public void repeat(String tradeState, Map<String, Object> wechatinfo) { //延迟执行的线程池, 核心线程数以自己的服务器cpu去计算; ScheduledExecutorService service = newScheduledThreadPool(cpuNum+1); Map<String, String> queryReq = new HashMap<>(); queryReq.put("outTradeNo", wechatinfo.get("out_trade_no")); queryReq.put("spmchid", wechatinfo.get("sp_mchid")); queryReq.put("submchid", wechatinfo.get("sub_chid")); //此方法无论执行时间长短,都是当一个任务执行完成之后,延退指定时间再开始执行第二个任务 service.scheduleAtFixedRate(new Runnable() { int count = 1;//计数器 count:初始为,Max=5; @Override public void run() { if (count < 6 && "USERPAYING".equals(tradeState)) { //调用查询接口,新该订单状态(这部分是去调你的查询接口,大同小异自己修改一下) log.info("queryorder 第" + count + "次轮询 start" + queryReq); Commonresponse queryOrderResp = wechatTranInfo.queryOrder(queryReq); log.info("queryorder 第" + count + "次轮询 end" + queryOrderResp); Map<String, Object> queryResp = (Map) queryOrderResp.getResult(); String trade_state = StringUtil.nvl(queryResp.get("trade_state")); count++; //判断查询是否成功及订单状态是否USERPAYING,不为USERPAYING就去更新订单表; if ("0".equals(queryOrderResp.getTransok()) && "IUSERPAYING".equals(trade_state)) { Map<String, Object> map = fovaOrderInfo.updatebygtcg(queryResp); log.info("支付更新订单表结果" + map); service.shutdown(); } } else { //超时撤单,(这部分是去调你的撤销订单接口,大同小异自己修改一下) log.info("revokeorder超时撤单 start" + queryReq); Commonresponse revokeResp = wechatTranVoid.revokeOrder(queryReq); String trade_state = "0".equals(revokeResp.getTransok()) ? "REVOKED" : "NREVOKED"; //更新订单表入参 HashMap<String, Object> revokeOrderIntput = new HashMap<>(); //新增类型,撤销 revokeOrderIntput.put("trade_ state", trade_state);//设置订单状态 revokeOrderIntput.put("out trade_no", wechatinfo.get("out_trade_no"));//设置商户订单号 Map<String, Object> map = fovaorderinfo.updateByGtcg(revokeOrderIntput);//更新订单表 log.info("撤单更新订单表结果" + map); service.shutdown(); } } }, 5, 10, TimeUnit.NANOSECONDS); }