HashMap为什么是线程不安全的

首先HashMap在jdk1.7和1.8之间的实现略有不同。在jdk1.7版本中为了解决hash冲突采用了头插法来形成一个链表。jdk1.8采用了尾插法。接下来分别针对这两种情况来讲解
一、jdk1.7版本
(1)在多线程环境下,如果hashmap是一个共享资源,那么在扩容的情况下,其会出现死循环。
其中头插法的部分代码:
void transfer(Entry[] newTable, boolean rehash){
   int newCapacity = newTable.length;
   for(Entry e : table){
     while(null != e){
        Entry next = e.next;
        if(rehash){
          e.hash = null == e.key ? 0 : hash(e.key);
        }
        int i = indexFor(e.hash, newCapacity);
        e.next = newTable[i];
        newTable[i] = e;
        e = next;
       }
   }
}
(2)扩容过程中如果发生了死循环,那么原数组中后续的数据会丢失

二、jdk1.8版本
在jdk1.8中对hashMap进行了优化,在发生hash碰撞,不再采用头插法方式,而是直接插入链表尾部,因此不会出现环形链表的情况,但是在多线程的情况下仍然不安全。
在put时,如果没有hash碰撞则会直接插入元素。假设此时线程A和线程B同时进行put操作,刚好这两条数据对应的hash值一样,并且该位置数据为null,所以线程A,B都会进行直接插入,如果线程A判断该位置为null后还未进行数据插入时挂起,而线程B正常执行,从而正常插入数据,然后线程A获取CPU时间片,此时线程A不用再进行hash判断了,问题出现:线程A会把线程B插入的数据给覆盖,发生线程不安全。

你可能感兴趣的:(HashMap为什么是线程不安全的)