HashMap为什么线程不安全以及解决方法
来源:互联网 发布:高仿表 知乎 编辑:程序博客网 时间:2024/04/29 19:38
众所周知,hashmap线程不安全而hashtable线程安全。最近在看并发编程就稍微研究了一下。先看一段JAVAAPI中对hashmap的介绍:
*注意,此实现不是同步的。如果多个线程同时访问此映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的不同步访问,如下所示:
Map m = Collections.synchronizedMap(new HashMap(…));*
hashmap的底层是一个链表散列(数组与链表的结合体)。
1. void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
hashmap在调用put方法时会调用上面方法,假若现在同时有A线程和B线程同时获得了同一个头节点并对其进行修改,这样A写入头节点之后B也写入头节点则会将A的操作覆盖
2.
final Entry<K,V> removeEntryForKey(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; while (e != null) { Entry<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
这上面是删除操作,同样的如果一个头节点的元素同时被两个线程删除,则又会造成混乱。
3.
`void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); } `以上是hashmap的增加容量的操作,如果同时A,B两个线程都要执行resize()操作,A线程已经进行在原基础的扩容,B线程也在原基础上扩容,这样就会造成线程不安全。下面写一个例子来验证一下
import java.util.HashMap;import java.util.Random;import java.util.concurrent.atomic.AtomicInteger;public class hashMap { static void dos(){ HashMap<Long,String> ss=new HashMap<Long,String>(); final AtomicInteger in=new AtomicInteger(0); ss.put(0L, "ssssssss"); for(int i=0;i<200;i++){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub ss.put(System.nanoTime()+new Random().nextLong(),"ssssssssssss"); String s=ss.get(0L); if(s==null){ in.incrementAndGet(); } } }).start(); } System.out.println(in); } public static void main(String[] args) { for(int i=0;i<10;i++){ dos(); }}}
结果并不都是0
但是如果将hashmap的初始大小设的大一些就不会出现这种情况。
下来研究一下如何使hashmap线程安全
http://flyfoxs.iteye.com/blog/2100120
//两种方式让hashmap线程安全
1.第一种办法api中已经有指出
如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的不同步访问,如下所示:
Map m = Collections.synchronizedMap(new HashMap(…));
即使用Collections.synchronizedMap()来返回一个新的map,但是这个返回的是不是hashmap,而是一个map的实现
第二种办法是改写hashmap。//暂时正在研究源码。。。
- HashMap为什么线程不安全以及解决方法
- hashmap为什么线程不安全
- HashMap为什么线程不安全
- HashMap为什么线程不安全
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- HashMap为什么是线程不安全的?
- 为什么HashMap是线程不安全的
- 为什么HashMap是线程不安全类?
- HashMap为什么是线程不安全的?
- HIToj--1076--Ordered Fractions(水题)
- 如何将tabbar隐藏掉
- Android开发中怎样使用cookieManager来管理cookie
- 子数组之和_LintCode
- C++ stringstream介绍,使用方法与例子
- HashMap为什么线程不安全以及解决方法
- 数据流中所有数排序之后的中位数
- 【动态规划】:poj2567,Tug of War
- spring和spring mvc配置文件context加载的区
- python基础教程共60课-第29课连接list
- Masonry介绍与使用实践
- 对一幅图像添加高斯噪声
- 单例模式----设计模式系列
- JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释