HashMap总结

Posted wchxj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashMap总结相关的知识,希望对你有一定的参考价值。

 

HashMap的结构图(链表离散的数据结构,即数据加单向链表结构)

技术分享图片

归纳

简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。

HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,

会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,

也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

Fail-Fast机制

我们知道java.util.HashMap不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。

 

HashMap为什么线程不安全

表现1:

多个线程同时操作一个hashmap就可能出现不安全的情况:

比如A B两个线程(A线程获数据 B线程存数据) 同时操作myHashMap
1.B线程执行存放数据
modelHashMap.put("1","2");
2.A线程执行get获取数据
modelHashMap.get("1")
A线程获取的值本来应该是2,但是如果A线程在刚到达获取的动作还没执行的时候,

线程执行的机会又跳到线程B,此时线程B又对modelHashMap赋值 如:modelHashMap.put("1","3");

然后线程虚拟机又执行线程A,A取到的值为3,这样map中第一个存放的值 就会丢失。。。。。

要保证值的准确,就要保证操作的原子性,就是保证A操作从头开始不能被打断。。所有要用同步关键字,

或者使用java 1.5中的current新包中的ConcurrentHashMap,这是线程安全的,在java最新的并发包中,对之前非线程安全的工具,如hashMap List 都做了同步封转。

表现2:

一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:HashMap(int initialCapacity, float loadFactor),其中参数initialCapacity为初始容量,

loadFactor为加载因子,而之前我们看到的threshold = (int)(capacity * loadFactor); 如果在默认情况下,一个HashMap的容量为16,加载因子为0.75,那么阀值就是12,所以在往HashMap中put的值到达12时,它将自动扩容两倍,如果两个线程同时遇到HashMap的大小达到12的倍数时,就很有可能会出现在将oldTable转移到newTable的过程中遇到问题,从而导致最终的HashMap的值存储异常。

表现3:

构造entry<K,V>单链表时,也会出现不安全的情况。

个人总结:个人觉得HashMap在并发时可能出现的问题主要是两方面,首先如果多个线程同时使用put方法添加元素,而且假设正好存在两个put的key发生了碰撞(hash值一样),

那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终就会发生其中一个线程的put的数据被覆盖。第二就是如果多个线程同时检测到元素个数超过数组大小*loadFactor,

这样就会发生多个线程同时对Node数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失。

解决方案:

  • Hashtable
  • ConcurrentHashMap
  • Synchronized Map

 

 






以上是关于HashMap总结的主要内容,如果未能解决你的问题,请参考以下文章

HashMap相关总结

HashMap总结

2018/6/29 关于hashmap的总结

总结一下hashMap和hashtable方面的知识点

HashMap相关总结

HashMap概述与用法总结