Java 中 ConcurrentHashMap 和 HashMap 的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Luckyray
V2EX    Java

Java 中 ConcurrentHashMap 和 HashMap 的问题

  •  
  •   Luckyray 2018-12-12 21:39:16 +08:00 3499 次点击
    这是一个创建于 2545 天前的主题,其中的信息可能已经有所发展或是发生改变。

    遇到这么一个问题,后台多线程执行一个长时间的大量的任务,前台通过轮训查询任务进度。

    任务进度放在一个 ConcurrentHashMap 中,然后每个线程执行完一次任务就在这个 map 里面的 index+1。然后这个 map 再放在另一个静态的 ConcurrentHashMap 里面,key 是批次号。

    然后前台查询任务进度时候是这样:静态的 map.get(批次号).get(index)得到已经完成的任务数。

    也就是说外面那个 map 存储的是里面 map 的引用,然后里面 map 的内容一直在变化。但是前端查询进度的时候,得到的数字一直是 0。

    外面 map 换成 HashMap 之后问题消失,有点好奇这里是不是跟 ConcurrentHashMap 的特性有关?是不是存储引用的时候会保存一个副本之类的?

    13 条回复    2018-12-14 11:10:12 +08:00
    11wangyaoda
        1
    11wangyaoda  
       2018-12-12 21:44:26 +08:00   1
    照理说 Java 8 CHM 的 Node 都是 volatile 的。可见性应该没啥问题啊。
    wdlth
        2
    wdlth  
       2018-12-12 21:46:22 +08:00
    用 AtomicInteger 呢?
    sagaxu
        3
    sagaxu  
       2018-12-12 21:48:32 +08:00 via Android
    没看明白 index 是个什么东西,又如何 index+1
    misaka19000
        4
    misaka19000  
       2018-12-12 22:05:18 +08:00
    上代码,你这样讲会有些遗漏的部分,不够完整
    hwding
        5
    hwding  
       2018-12-13 08:58:50 +08:00 via iPhone
    会不会因为锁偏向的原因 get 一直获得锁然后值就写不进去?
    shanigan
        6
    shanigan  
       2018-12-13 09:05:38 +08:00
    map 都是 key value pair,为什么会有 index。你每次都 index+1,key 不都改变了?结果 value 肯定都是 0
    Kaiv2
        7
    Kaiv2  
       2018-12-13 09:56:04 +08:00
    map.get(批次号).get(index),index + 1 ? 还能取到数据?/div>
    Luckyray
        8
    Luckyray  
    OP
       2018-12-13 10:14:28 +08:00
    我错了...是语言描述能力太捉鸡了么,写一段伪代码:
    class{
    ConcurrnetHashMap outerMap=new ConcurrentHashMap();

    获取任务进度的函数(){
    outerMap.get(batchNum).get("success");
    }

    任务处理的函数(){
    ConcurrentHashMap innerMap=new ConcurrentHashMap();
    innerMap.put("success",0);
    outerMap.put(batchNum,innerMap);
    foreach(task:tasks){
    ThreadPool.execute(() -> {
    innerMap.put("success",innerMap.get("success")+1)
    })
    }
    }
    }
    @Kaiv2 @shanigan @sagaxu @misaka19000
    Kaiv2
        9
    Kaiv2  
       2018-12-13 10:23:11 +08:00   1
    innerMap.put("success",innerMap.get("success")+1) 换成 AtomicInteger.incrementAndGet() 试试
    misaka19000
        10
    misaka19000  
       2018-12-13 10:32:45 +08:00   2
    innerMap.put("success",innerMap.get("success")+1)

    这一行不是线程安全的
    cyspy
        11
    cyspy  
       2018-12-13 11:09:39 +08:00   1
    不想用 AtomicInteger 的话可以考虑用 merge
    GreatEscape
        12
    GreatEscape  
       2018-12-13 11:41:11 +08:00   1
    提供个思路,batchNum 是不是有问题,为 Null ?
    CHM 是不允许 Null Key 的,但是 HashMap 允许。
    lilyblooper
        13
    lilyblooper  
       2018-12-14 11:10:12 +08:00
    innerMap.get("success")+1 这个不是 thread-safe 的。
    换成 atomic* 类
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     831 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 22:06 PVG 06:06 LAX 14:06 JFK 17:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86