HashMap 多线程问题

2015-08-04 02:35:02 +08:00
 final0pro

一个hashmap,多个线程访问

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

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

会不会出现问题?

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

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

求指点。谢谢。

2995 次点击
所在节点    问与答
18 条回复
Valyrian
2015-08-04 03:04:19 +08:00
ConcurrentHashMap
final0pro
2015-08-04 03:53:24 +08:00
@Valyrian 对,这个肯定可以。

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

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

但是我的这种情况,一个只是get,永远不会rehash整个hashmap,所以应该不会出现死循环吧
introom
2015-08-04 04:29:48 +08:00
@final0pro 最不理解这种回答完全和问题不相关的,这个感情是对问题的侮辱啊
final0pro
2015-08-04 04:47:56 +08:00
@introom T_T
Andiry
2015-08-04 05:01:11 +08:00
我不认为有啥问题,因为hashmap的reassign是原子的
除非hashmap.get()当中又使用了hashmap本身
final0pro
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
2015-08-04 05:35:50 +08:00
@final0pro 只要这三步按照顺序来就没问题,因为第三步是原子的,get线程永远不会看到NULL
当然像那篇文章里说的重排序就挂了
final0pro
2015-08-04 05:50:53 +08:00
@Andiry 除了这种情况,会不会还有另外一种可能?:

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

thread2: reassign了新的hashmap

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

感觉是有这个可能的,但是要在极度高并发的情况才有可能?
Andiry
2015-08-04 05:59:44 +08:00
@final0pro 不会。即使thread2 reassign了hashmap,get访问的hashmap仍然是旧的那一个。除非旧hashmap在这个get过程当中被GC了。
qiyi
2015-08-04 06:51:02 +08:00
hashMap要么是旧的Map要么是新的Map ,没啥问题,copyonwritehashmap就这么实现
final0pro
2015-08-04 08:04:28 +08:00
@Andiry 懂了。谢谢!
SoloCompany
2015-08-04 08:45:12 +08:00
加 violite 关键字
laipogo
2015-08-04 09:04:52 +08:00
@SoloCompany
volatile
mind3x
2015-08-04 09:47:52 +08:00
@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
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
2015-08-05 02:17:54 +08:00
@mind3x 确实,应该添加volarile 关键字,感谢。
qiyi
2015-08-05 02:19:25 +08:00
手机打字,纠正上面单词错误 ,volatile
Karlllll
2016-08-09 23:28:25 +08:00
题主,你的问题好像。。。。。
get 访问跟你重新把一个指针指向一个新的 hashMap ,没有关系。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/210588

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX