V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
final0pro
V2EX  ›  问与答

HashMap 多线程问题

  •  
  •   final0pro · 2015-08-04 02:35:02 +08:00 · 2964 次点击
    这是一个创建于 3398 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个hashmap,多个线程访问

    一个读线程调用hashMap.get("xx")

    一个写线程重新赋值 hashMap = new HashMap()

    会不会出现问题?

    比如读的过程刚拿到key哈希之后的值,这个时候另一个线程重新assign了一个新的hashmap,这个理论上是会出问题的吧?

    写了几个测试,都pass了,但是感觉不靠谱啊。

    求指点。谢谢。

    18 条回复    2016-08-09 23:28:25 +08:00
    Valyrian
        1
    Valyrian  
       2015-08-04 03:04:19 +08:00 via iPhone
    ConcurrentHashMap
    final0pro
        2
    final0pro  
    OP
       2015-08-04 03:53:24 +08:00
    @Valyrian 对,这个肯定可以。

    但是我是想确定下,这种情况用hashmap会不会出现问题,出现什么样的问题?

    一般hashmap并发出现死循环,是因为二个线程同时在rehash同一个hashmap

    但是我的这种情况,一个只是get,永远不会rehash整个hashmap,所以应该不会出现死循环吧
    introom
        3
    introom  
       2015-08-04 04:29:48 +08:00
    @final0pro 最不理解这种回答完全和问题不相关的,这个感情是对问题的侮辱啊
    final0pro
        4
    final0pro  
    OP
       2015-08-04 04:47:56 +08:00
    @introom T_T
    Andiry
        5
    Andiry  
       2015-08-04 05:01:11 +08:00
    我不认为有啥问题,因为hashmap的reassign是原子的
    除非hashmap.get()当中又使用了hashmap本身
    final0pro
        6
    final0pro  
    OP
       2015-08-04 05:13:22 +08:00
    @Andiry google了一下,assignment好像不是原子的

    http://coolshell.cn/articles/265.html

    ```
    主要在于singleton = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。

    给 singleton 分配内存
    调用 Singleton 的构造函数来初始化成员变量,形成实例
    将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null 了)
    ```

    那这样,岂不是有可能会NullPointerException。。。null.get("xx")了。。。
    Andiry
        7
    Andiry  
       2015-08-04 05:35:50 +08:00
    @final0pro 只要这三步按照顺序来就没问题,因为第三步是原子的,get线程永远不会看到NULL
    当然像那篇文章里说的重排序就挂了
    final0pro
        8
    final0pro  
    OP
       2015-08-04 05:50:53 +08:00
    @Andiry 除了这种情况,会不会还有另外一种可能?:

    thread1: get --》 拿到hash(key)的值 -》 线程被挂起

    thread2: reassign了新的hashmap

    thread1:被唤醒,因为之前已经拿到hash(key)了,所以继续拿这个去array中找,但是key这个时候可能已经全被打乱了

    感觉是有这个可能的,但是要在极度高并发的情况才有可能?
    Andiry
        9
    Andiry  
       2015-08-04 05:59:44 +08:00   ❤️ 1
    @final0pro 不会。即使thread2 reassign了hashmap,get访问的hashmap仍然是旧的那一个。除非旧hashmap在这个get过程当中被GC了。
    qiyi
        10
    qiyi  
       2015-08-04 06:51:02 +08:00 via iPhone   ❤️ 1
    hashMap要么是旧的Map要么是新的Map ,没啥问题,copyonwritehashmap就这么实现
    final0pro
        11
    final0pro  
    OP
       2015-08-04 08:04:28 +08:00
    @Andiry 懂了。谢谢!
    SoloCompany
        12
    SoloCompany  
       2015-08-04 08:45:12 +08:00 via iPhone
    加 violite 关键字
    laipogo
        13
    laipogo  
       2015-08-04 09:04:52 +08:00
    @SoloCompany
    volatile
    mind3x
        14
    mind3x  
       2015-08-04 09:47:52 +08:00 via Android   ❤️ 2
    @Andiry @qiyi 知道为什么 double checked locking 是错的吗?这里也是一样有 memory reordering 的问题,除非显式插入 barrier 保证顺序。

    @final0pro 建议阅读老文 http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html
    final0pro
        15
    final0pro  
    OP
       2015-08-04 23:33:43 +08:00
    @mind3x 学习了

    但是这篇文章是2001年,java1.5诞生之前

    根据http://coolshell.cn/articles/265.html这篇,

    ```
    但是,这个事情仅在Java 1.5版后有用,1.5版之前用这个变量也有问题,因为老版本的Java的内存模型是有缺陷的。
    ```

    现在应该没问题了
    qiyi
        16
    qiyi  
       2015-08-05 02:17:54 +08:00 via iPhone
    @mind3x 确实,应该添加volarile 关键字,感谢。
    qiyi
        17
    qiyi  
       2015-08-05 02:19:25 +08:00 via iPhone
    手机打字,纠正上面单词错误 ,volatile
    Karlllll
        18
    Karlllll  
       2016-08-09 23:28:25 +08:00
    题主,你的问题好像。。。。。
    get 访问跟你重新把一个指针指向一个新的 hashMap ,没有关系。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   960 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 431ms · UTC 21:50 · PVG 05:50 · LAX 13:50 · JFK 16:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.