栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程使用redis进行累加结果不对解决方案

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程使用redis进行累加结果不对解决方案

多线程使用redis进行累加结果不对解决方案
  • 问题背景
  • 解决方案
  • 总结
  • 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> futureResult = asyncServiceExecutor.submit(() -> submitSingle(globalId, params));
	Map resultVOList = futureResult.get();
	if(resultVOList != null){
		Object commitObject = redisUtils.get(globalId);
		if (commitObject == null) {
		    boolean flag = redisUtils.set(globalId, params.size());
		} else {
		    redisUtils.increment(globalId, (long) params.size());
		}
	}
}

public Map submitSingle(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 …

Lyric: 如果难过请你忘了我 这是第4首歌,已经完结了,你们猜出歌名了吗?
  • 歌名:借口
  • 歌手:周杰伦
  • 歌词:周杰伦
  • 专辑:七里香
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/831895.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号