V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
crossoverJie
V2EX  ›  程序员

一次 HashSet 所引起的并发问题

  •  4
     
  •   crossoverJie ·
    crossoverJie · Nov 9, 2018 · 3305 views
    This topic created in 2734 days ago, the information mentioned may be changed or developed.

    一次 HashSet 所引起的并发问题

    大家都在说的 HashMap 并发问题居然真碰上了🤣.

    18 replies    2018-11-09 16:59:40 +08:00
    mortonnex
        1
    mortonnex  
       Nov 9, 2018 via iPhone
    点赞
    YAHIKO0
        2
    YAHIKO0  
       Nov 9, 2018
    d=====( ̄▽ ̄*)b
    crossoverJie
        3
    crossoverJie  
    OP
       Nov 9, 2018
    @YAHIKO0 #2

    兄弟你这颜表情是啥意思

    jy02201949
        4
    jy02201949  
       Nov 9, 2018
    @crossoverJie #3 智能送分机器人
    YAHIKO0
        5
    YAHIKO0  
       Nov 9, 2018
    点赞,
    @crossoverJie
    coolcfan
        6
    coolcfan  
       Nov 9, 2018 via Android
    可以直接 Collections.newSetFromMap(new ConcurrentHashMap ()),无缝替换掉,省掉手动写死 value
    crossoverJie
        7
    crossoverJie  
    OP
       Nov 9, 2018
    @coolcfan #6

    嗯 本质上原理是一样的。
    aimaodeyuer
        8
    aimaodeyuer  
       Nov 9, 2018
    追踪问题的能力还是要向大佬学习!
    amon
        9
    amon  
       Nov 9, 2018
    点赞,这个问题只是理论上听到过,还真没看到过,哈哈。
    Jokerrrrrr
        10
    Jokerrrrrr  
       Nov 9, 2018
    分析排查的,有点厉害
    Antidictator
        11
    Antidictator  
       Nov 9, 2018
    点赞+1
    TommyLemon
        12
    TommyLemon  
       Nov 9, 2018
    赞。
    我第一次看到 HashSet 的实现源码也震惊了,居然是用 HashMap 实现的,
    HashSet 里的所有 value 存到了 HashMap 里的所有 key,HashMap 的 value 则是全局的
    private static final Object PRESENT = new Object();
    文中用 ConcurrentHashMap 替代 HashSet 并写死 value 的做法,
    其实就是把 HashSet 简单地重新实现了一遍,并保证线程安全。
    TommyLemon
        13
    TommyLemon  
       Nov 9, 2018
    @TommyLemon 至于形成环形链表的原因我看到问题就猜出来是
    多线程并发执行
    set.add(key)
    时同一个 key 被添加多次,然后导致
    valueI = key
    valueJ = key
    当循环里通过
    value = value.next
    形成了从 valueI 到 valueJ 的环形链表
    BBCCBB
        14
    BBCCBB  
       Nov 9, 2018
    这..... 这难道不是常识吗?


    Collections.newSetFromMap(new ConcurrentHashMap<>())
    crossoverJie
        15
    crossoverJie  
    OP
       Nov 9, 2018
    @TommyLemon #12

    是的,所以把实现的时候简单封装个类就可以了。
    crossoverJie
        16
    crossoverJie  
    OP
       Nov 9, 2018
    @BBCCBB #14

    我确实是很少用 Collections.newSetFromMap 这个 API,有并发 set 要求都是用自己封装的 ConcurrentHashMap,不过原理都是一样的,不用过多纠结。
    x66
        17
    x66  
       Nov 9, 2018
    感觉 Set 是为了去重,感觉 Redis 更适合干这事。
    crossoverJie
        18
    crossoverJie  
    OP
       Nov 9, 2018
    @x66 #17

    Redis 当然可以。这本来就是个祖传代码,所以想最快的改造上线。

    加上其实我们的场景没必要用 Redis,就内存操作还更快。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   993 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 48ms · UTC 23:18 · PVG 07:18 · LAX 16:18 · JFK 19:18
    ♥ Do have faith in what you're doing.