当前位置:编程学习 > JAVA >>

hashMap 线程安全问题

多线程从hashmap中get 同时一个线程在put,这个时候会出现问题么?
--------------------编程问答-------------------- --------------------编程问答-------------------- hi.只要多个线程同时操作一个hashmap就可能出现这种情况。
比如A B两个线程 同时操作modelHashMap
A线程获数据 B线程存数据
1.B线程执行存放数据
modelHashMap.put("1","2");
2.A线程执行get获取数据
modelHashMap.get("1")
它的值本来应该是2,但是如果A线程在刚到达获取的动作还没执行的时候,
线程执行的机会又跳到线程B,此时线程B又对modelHashMap赋值 如:modelHashMap.put("1","3");
然后线程虚拟机又执行线程A,A取到的值为3,这样map中第一个存放的值 就会丢失。。。。。
要保证值的准备,就要保证操作的原子性,就是保证我的操作从头开始不能被打断。。所有要用同步关键字,当然也可以使用java 1.5中的current新包中的ConcurrentHashMap,这是线程安全的,在java最新的并发包中,对之前非线程安全的工具,如hashMap List 都做了同步封转,可以看一下哦 。。。。。 --------------------编程问答--------------------
引用 2 楼 nyliyan8410 的回复:
hi.

如果我重写了hashmap的方法,加上线程锁,那么get 和put 不能同时操作了对吧 --------------------编程问答-------------------- --------------------编程问答-------------------- 同步一般只对写入进行考虑,读取来说,没有太大的必要进行锁定
而且,java1.5以后可以采用 ConcurrentHashMap 这个是线程安全的 --------------------编程问答-------------------- 老问题了:http://www.ticmy.com/?p=97 --------------------编程问答-------------------- public class ConcurrentHashMap<K,V>extends AbstractMap<K,V>implements ConcurrentMap<K,V>, Serializable支持获取的完全并发和更新的所期望可调整并发的哈希表。此类遵守与 Hashtable 相同的功能规范,并且包括对应于 Hashtable 的每个方法的方法版本。不过,尽管所有操作都是线程安全的,但获取操作不 必锁定,并且不 支持以某种防止所有访问的方式锁定整个表。此类可以通过程序完全与 Hashtable 进行互操作,这取决于其线程安全,而与其同步细节无关。
获取操作(包括 get)通常不会受阻塞,因此,可能与更新操作交迭(包括 put 和 remove)。获取会影响最近完成的 更新操作的结果。对于一些聚合操作,比如 putAll 和 clear,并发获取可能只影响某些条目的插入和移除。类似地,在创建迭代器/枚举时或自此之后,Iterators 和 Enumerations 返回在某一时间点上影响哈希表状态的元素。它们不会 抛出 ConcurrentModificationException。不过,迭代器被设计成每次仅由一个线程使用。
这允许通过可选的 concurrencyLevel 构造方法参数(默认值为 16)来引导更新操作之间的并发,该参数用作内部调整大小的一个提示。表是在内部进行分区的,试图允许指示无争用并发更新的数量。因为哈希表中的位置基本上是随意的,所以实际的并发将各不相同。理想情况下,应该选择一个尽可能多地容纳并发修改该表的线程的值。使用一个比所需要的值高很多的值可能会浪费空间和时间,而使用一个显然低很多的值可能导致线程争用。对数量级估计过高或估计过低通常都会带来非常显著的影响。当仅有一个线程将执行修改操作,而其他所有线程都只是执行读取操作时,才认为某个值是合适的。此外,重新调整此类或其他任何种类哈希表的大小都是一个相对较慢的操作,因此,在可能的时候,提供构造方法中期望表大小的估计值是一个好主意。 
此类及其视图和迭代器实现了 Map 和 Iterator 接口的所有可选 方法。
此类与 Hashtable 相似,但与 HashMap 不同,它不 允许将 null 用作键或值。
此类是 Java Collections Framework 的成员。
从以下版本开始: 
1.5 
--------------------编程问答-------------------- 加上 sync 块吧 --------------------编程问答--------------------
引用 3 楼 lanhao124 的回复:
引用 2 楼 nyliyan8410 的回复:
hi.
如果我重写了hashmap的方法,加上线程锁,那么get 和put 不能同时操作了对吧


可以的 ,不过现在java 已经实现了,没必要自己再搞一个。
如果要自己写的话,要注意用读写锁,即:多个线程可以同时读,但只有一个线程可同写。不然数据量大的时候也会影响性能。 --------------------编程问答-------------------- 除 --------------------编程问答--------------------
引用 6 楼 ticmy 的回复:
老问题了:http://www.ticmy.com/?p=97
我的环境是最多一个线程写,多个线程去读! --------------------编程问答--------------------
引用 11 楼 lanhao124 的回复:
引用 6 楼 ticmy 的回复:老问题了:http://www.ticmy.com/?p=97我的环境是最多一个线程写,多个线程去读!


只要有put就有写,就有可能重hash,不想同步就用ConcurrentHashMap --------------------编程问答--------------------
引用 11 楼 lanhao124 的回复:
引用 6 楼 ticmy 的回复:老问题了:http://www.ticmy.com/?p=97我的环境是最多一个线程写,多个线程去读!


用ConcurrentHashMap挺好的,支持高并发的!只是写的时候才lock,value声明volatile,可以支持读取的并发。
如果你觉得还是不爽的话,自己封装一下实现CAS也行,每次put的时候,带一个旧值校验,就像数据库的:
update set abc=newValue where abc=oldValue
如果失败,再重试!  (但是要保证校验相等的时候,不能被其他线程影响,还是需要同步) 哈哈
补充:Java ,  Java EE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,