在实际开发中可能存在多线程高并发调用hashmap的情况,首先要了解什么是hashmap,hashmap浅析
一、hashmap多线程并发时存在的问题
Hashmap不是线程安全的。在高并发环境下做插入操作,有可能出现下面的环形链表:
首先要了解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的长度

/**
* Transfers all entries from current table to newTable.
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> 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)