- 问题背景
- 解决方案
- 总结
- Lyric: 如果难过请你忘了我
- 这是第4首歌,已经完结了,你们猜出歌名了吗?
在使用多线程进行对redis的value做累加时导致出错,使用伪代码进行原因分析
for(int i=0;i<10;i++){
//提交10个线程,每个params装有10条数据
asyncServiceExecutor.submit(() -> submitSingle(globalId, params));
}
public Map submitSingle(String globalId, JSONArray params) {
try {
log.info("params: {}, size: {}", params, params.size());
Map resultVOlist = QueryController.doQuery(params);
//由于是多核,可以做到真正意义上同时间的并发,因此可能会出现有5个线程同时到达了这条语句
//第一次同时达到,redis里面就是没有这个globalId关键字,因此5个线程都是为null
Object commitObject = redisUtils.get(globalId);
//当有5个为null的线程进来之后,就会导致多次创建了同一个键,累加数据相当于丢失了4次,也就是40条
if (commitObject == null) {
boolean flag = redisUtils.set(globalId, params.size());
} else {
redisUtils.increment(globalId, (long) params.size());
}
return resultVOlist;
} catch (Exception e) {
log.error("QueryController not found error", e);
return new HashMap<>();
}
}
解决方案
1 既然是多线程产生的原因,那么我们可以把写redis的写操作移出到主线程,redis的底层写操作是单线程的
for(int i=0;i<10;i++){
//提交10个线程,每个params装有10条数据
Future
public MapsubmitSingle(String globalId, JSONArray params) { try { log.info("params: {}, size: {}", params, params.size()); Map resultVOlist = QueryController.doQuery(params); return resultVOlist; } catch (Exception e) { log.error("QueryController not found error", e); return new HashMap<>(); } }
2 可以在线程里面把写redis的逻辑进行整体加锁
public Map总结submitSingle(String globalId, JSONArray params) { try { log.info("params: {}, size: {}", params, params.size()); Map resultVOlist = QueryController.doQuery(params); if(redission.lock(uuid)){ Object commitObject = redisUtils.get(globalId); if (commitObject == null) { boolean flag = redisUtils.set(globalId, params.size()); } else { redisUtils.increment(globalId, (long) params.size()); } } return resultVOlist; } catch (Exception e) { log.error("QueryController not found error", e); return new HashMap<>(); } }
- 问题只会越来越多,但也要耐心解决
作为程序员第 115 篇文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha …
- 歌名:借口
- 歌手:周杰伦
- 歌词:周杰伦
- 专辑:七里香



