java 多线程并发下的HashMap

在实际开发中可能存在多线程高并发调用hashmap的情况,首先要了解什么是hashmap,hashmap浅析

一、hashmap多线程并发时存在的问题

Hashmap不是线程安全的。在高并发环境下做插入操作,有可能出现下面的环形链表:

java 多线程并发下的HashMap_第1张图片

首先要了解rehash,rehash是hashmap扩容时的一个步骤。

由于hashmap的长度是有限的,当经过多次元素的插入,hashmap可用长度变小,key值映射位置发生冲突的几率也会变大,这时候hashmap就会扩充它的长度,也就是扩容(resize

影响发生Resize的因素有两个:


1.Capacity

HashMap的当前长度。一般来说,HashMap的长度是2的幂。


2.LoadFactor

HashMap负载因子,默认值为0.75f。

衡量HashMap是否进行Resize的条件如下:


HashMap.Size   >=  Capacity * LoadFactor

也就是当已用长度是总长度的75%时,hashmap会扩容resize

resize会有两个步骤


1.扩容

创建一个新的Entry空数组,长度是原数组的2倍。



2.ReHash

遍历原Entry数组,把所有的Entry重新Hash到新数组。为什么要重新Hash呢?因为长度扩大以后,Hash的规则也随之改变。

index =  HashCode(Key) &  (Length - 1)

length是hashmap的长度


java 多线程并发下的HashMap_第2张图片
rehash源码:
/**
 * Transfers all entries from current table to newTable.
 */
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;
        }
    }
}

那么为什么在多线程并发的时候hashmap会出现什么问题呢

参考

https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653192000&idx=1&sn=118cee6d1c67e7b8e4f762af3e61643e&chksm=8c990d9abbee848c739aeaf25893ae4382eca90642f65fc9b8eb76d58d6e7adebe65da03f80d&scene=21#wechat_redirect

总结一下就是:

1.Hashmap在插入元素过多的时候需要进行Resize,Resize的条件是

HashMap.Size   >=  Capacity * LoadFactor。


2.Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环。

二、怎么保证hashmap是线程安全的

(1)改用hashtable或者Collections.synchronizeMap(这两者在读写操作时会给整个集合加锁,导致同一时间其他操作阻塞,影响性能)

(2)ConcurrentHashmap(保证线程安全,而且性能优于hashtable或者Collections.synchronizeMap)

你可能感兴趣的:(常用数据结构)