求知识,java redis抢红包问题

猫神jdx 2015-10-19 09:21:49
以下是模拟300人同时抢200个红包的实例,但是实际测试中,最后保存已拿红包的都是少于200人,是什么原因?是redis丢数据了还是其他的?

public Map<String, Object> autoGetRedPackage() throws Exception {
Map<String, Object> returnMap = new HashMap<String, Object>();
long companyId = 45243043L;

int max = 100;
int min = 2;
int total = 10000;
int count = 200;

//将大红包拆分成小红包数组
long[] rpDatas = RedPacketAlgorithm.generate(total, count, max, min);
logger.info("红包生成数:" + rpDatas.length);
// 将生成的红包放入队列中
final String key = "red_packet_auto_" + UUID.randomUUID().toString();
for (int i = 1; i <= rpDatas.length; i++) {
Msg msg = new Msg();
msg.setId(i);
msg.setMoney(rpDatas[i-1]);
msg.setSourceUserId(companyId);
try {
redisService.leftPush(key, msg);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return returnMap;
}
}

// 已经领取用户列表
final String mapKey = "hasGet_" + key;
// 最后生成的领取记录队列
final String finshKey = "finish_" + key;

/**
* 接收到一个获取红包请求 判断是否已经领取过 如果没有,则从redis队列中取出一个分给该用户 添加该用户的领取记录 如果没有,则返回已经领取完 将完成队列处理入库
*/
//模拟300人同时不同的抢红包
int threadNum = 300;

for (int i = 1; i <= threadNum; i++) {
final String temp = Integer.toString(i);
Thread thread = new Thread() {
public void run() {
try {
String lockKey = key + "_" + temp;
while (true) {
//加锁60秒
Object isForbidRedObject = redisService.getByValue(lockKey);
boolean isForbidRed = false;
if (isForbidRedObject != null) {
isForbidRed = (boolean) isForbidRedObject;
}
if (!isForbidRed) {
//60秒内只能点一次,防止并发多抢
redisService.insertByValue(lockKey, true, 60, TimeUnit.SECONDS);
//查看是否已领取队列
Object isGetRedObject = redisService.getByHash(mapKey, temp);
boolean isGetRed = false;
if (isGetRedObject != null) {
isGetRed = (boolean) isGetRedObject;
}
if (!isGetRed) {
try {
logger.info("size:" + redisService.getListQueueSize(key));
//弹出红包
Object data = redisService.rightPop(key);
if (data != null) {
LinkedHashMap map = (LinkedHashMap) data;
Msg msg = new Msg();
msg.setId((int) map.get("id"));
msg.setMoney((int) map.get("money"));
msg.setGetUserId(Long.parseLong(temp));
msg.setSourceUserId((int) map.get("sourceUserId"));
//插入到完成队列
redisService.leftPush(finshKey, msg);
//插入到已领取hast
redisService.insertByHash(mapKey, temp, true);
logger.info("恭喜[" + temp + "]用户," + "领红包成功,money:"
+ msg.getMoney());
break;
} else {
Long redPackageLength = redisService
.getListQueueSize(key);
if (redPackageLength == null || redPackageLength <= 0) {
logger.info("尊敬的[" + temp + "]用户," + "红包已经领取完了");
break;
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
} else {
logger.info("尊敬的[" + temp + "]用户,您已经领取过了,做人要厚道");
break;
}
}
Long redPackageLength = redisService.getListQueueSize(key);
if (redPackageLength == null || redPackageLength <= 0) {
logger.info("尊敬的[" + temp + "]用户," + "红包已经领取完了");
break;
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {

}

}
};
thread.start();
}

while (true) {
List<LinkedHashMap> end = redisService.getListQueue(key);
if (end == null || end.size() <= 0) {
break;
}
}

logger.info(redisService.getListQueueSize(key));
logger.info(redisService.getListQueueSize(finshKey));

List<LinkedHashMap> listFinish = redisService.getListQueue(finshKey);
List<Msg> returnRedPackageList = new ArrayList<Msg>();
for (LinkedHashMap map : listFinish) {
Msg msg = new Msg();
msg.setId((int) map.get("id"));
msg.setMoney((int) map.get("money"));
msg.setGetUserId((int) map.get("getUserId"));
msg.setSourceUserId((int) map.get("sourceUserId"));
returnRedPackageList.add(msg);
}
returnMap.put("result", returnRedPackageList);
return returnMap;
}
...全文
195 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
sinat_31535993 2015-10-20
  • 打赏
  • 举报
回复
这不就跟多线程的消费者模式一样吗,结果不对,应该是代码逻辑问题,开debug模式,一步一步跟进吧

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧