背景:产品需要,需消耗原有卡积分,转移到新卡。进行积分抽奖活动,其中用户可使用批量抽奖功能(10次)【单次请求第三方接口发送积分】。
分析:1 方法需进行防并发校验。【已有自定义注解,采用userId为key,redis进行防并发处理 ttl 获取-1 key没有设置失效时间; -2 key不存在; 正数 key的失效时间 】
2 采用单线程循环及多线程两种方法进行积分发放,redis中做开关切换
3 用户当日抽奖次数记redis,incry
关键代码实现:
public static final ExecutorService cachedThreadPool = Executors.newFixedThreadPool(50);
private Result<NewExpressResultVO> doReceivePacket(NewExpressCardReqDTO req,int times,NewExpressInfoBO acInfoCacheBO){
NewExpressResultVO newExpressResultVO = new NewExpressResultVO();
//成功赠送总金额
AtomicInteger totalAmt = new AtomicInteger(0);
//成功赠送次数
AtomicInteger totalTimes = new AtomicInteger(0);
CountDownLatch countDownLatch = new CountDownLatch(times);
if(acInfoCacheBO.getMultiThreadSwitch().equals("1")){
for(int i=0;i<times;i++){
cachedThreadPool.submit(()-> {
try {
sendPacket(totalTimes,totalAmt,req,times,newExpressResultVO,acInfoCacheBO.getMultiThreadSwitch());
}
catch (Exception e) {
logger.error("赠送金多线程抽奖失败 doReceivePacket 入参req{}",JSONObject.toJSONString(req));
}finally {
countDownLatch.countDown();
}
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
logger.error("赠送金多线程抽奖失败 doReceivePacket 入参req{}",JSONObject.toJSONString(req));
}
}else {
for(int i=0;i<times;i++){
sendPacket(totalTimes,totalAmt,req,times,newExpressResultVO,acInfoCacheBO.getMultiThreadSwitch());
}
}
newExpressResultVO.setTotalAmt(totalAmt.intValue());
newExpressResultVO.setTotalTimes(totalTimes.intValue());
return ResultUtil.success(newExpressResultVO);
}
//调用微服务发券
private void sendPacket(AtomicInteger totalTimes,AtomicInteger totalAmt,NewExpressCardReqDTO req,int times, NewExpressResultVO newExpressResultVO,String multiThreadSwitch){
Map<String, Object> sentPacketMap = sentCempPacketParams(req);
RestRespDTO<CommonPacketExchangeResult> result=null;
if(multiThreadSwitch.equals("1")) {
result = commonAcManager.receiveCommonActivityPacketList(sentPacketMap);
}else {
result = commonAcManager.receiveCommonActivityPacket(sentPacketMap);
}
if(result!=null && result.getSuccess()){
totalTimes.addAndGet(1);
totalAmt.addAndGet(result.getObj().getCommonAwardPacketRecordsResult().getCommodityCount());
DefaultRedisCache.hincrBy(TIMES_KEY,req.getUserId(),1);
if(DefaultRedisCache.ttl(TIMES_KEY)==-1) {
DefaultRedisCache.expire(TIMES_KEY, DateUtils.getRedisDate());
}
if(times==1){
newExpressResultVO.setPacketId(result.getObj().getCommonAwardPacketRecordsResult().getPacketId());
}
}
}