12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- package com.webchat.ugc.service.redpacket;
- import com.webchat.common.constants.RedPacketConstants;
- import com.webchat.common.enums.RedisKeyEnum;
- import com.webchat.common.exception.BusinessException;
- import com.webchat.domain.vo.response.RedPacketBaseVO;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.stereotype.Service;
- import java.math.BigDecimal;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.ThreadLocalRandom;
- /**
- * 方案三:预先计算好每分红包金额,走队列一次获取
- */
- @Service
- public class OpenRedPacketWithQueueService extends AbstractOpenRedPacketService {
- @Override
- public int openRedPacket(RedPacketBaseVO redPacket, String userId) {
- Long redPacketId = redPacket.getId();
- String queueKey = this.redPacketAmountQueueCacheKey(redPacket.getId());
- // 走队列获取预先计算好的红包金额,因为redis的单线程命令执行特性,所以这里是并发安全的
- String amount = redisService.lrightPop(queueKey);
- if (StringUtils.isBlank(amount)) {
- // 红包被拆分完
- super.updateRedPacketStatus(redPacketId, RedPacketConstants.RedPacketStatus.END);
- throw new BusinessException("来晚了,红包已拆完");
- }
- int amountVal = Integer.valueOf(amount);
- // 添加用户到红包拆分人员名单缓存
- addUser2OpenRedPacketUsersCache(redPacketId, userId);
- return amountVal;
- }
- public List<Integer> preGeneratedRedPackets(Long redPacketId, int totalMoneyFen, int gradCount) {
- List<Integer> redPackets = new ArrayList<>();
- // 递归生成红包金额
- this.doRecursivePreGenerated(totalMoneyFen, gradCount, redPackets);
- // 加入队列
- String queueKey = this.redPacketAmountQueueCacheKey(redPacketId);
- redisService.lleftPushAll(queueKey, redPackets);
- return redPackets;
- }
- private String redPacketAmountQueueCacheKey(Long redPacketId) {
- return RedisKeyEnum.QUEUE_RED_PACKET_AMOUNT.getKey(String.valueOf(redPacketId));
- }
- private void doRecursivePreGenerated(int balanceMoneyFen, int gradCountBalance, List<Integer> redPackets) {
- if (gradCountBalance == 1) {
- // 跳出条件
- redPackets.add(balanceMoneyFen);
- return;
- }
- // 二倍均值
- BigDecimal avgAmount = new BigDecimal(balanceMoneyFen).divide(new BigDecimal(gradCountBalance), 0, BigDecimal.ROUND_HALF_UP);
- BigDecimal avgAmount2 = avgAmount.multiply(new BigDecimal(2));
- int maxVal = avgAmount2.intValue();
- // 在[minVal, maxVal]之间随机一个红包金额:openAmount
- int openAmount = ThreadLocalRandom.current().nextInt(RedPacketConstants.MIN_AMOUNT, maxVal + 1);
- redPackets.add(openAmount);
- doRecursivePreGenerated(balanceMoneyFen - openAmount, gradCountBalance - 1, redPackets);
- }
- public static void main(String[] args) {
- List<Integer> redPackets = new ArrayList<>();
- int gradCount = 10;
- // 设置红包金额(分)
- int totalMoneyFen = new BigDecimal("100").multiply(new BigDecimal(100)).intValue();
- // 递归生成红包金额
- // doRecursivePreGenerated(totalMoneyFen, gradCount, redPackets);
- System.out.printf("预先计算好红包:" + redPackets);
- }
- }
|