更新 对于HashMap的一些疑问.md

This commit is contained in:
小柒2012
2018-09-02 12:50:48 +08:00
parent f1ac86f1da
commit 5f7f2bcefb

View File

@@ -134,6 +134,23 @@ jdk1.8在对hash冲突的key时如果此bucket位置上的元素数量在10
6.哈希值的使用不同HashTable直接使用对象的hashCode而HashMap重新计算hash值用与代替求
7.ConcurrentHashMap也是一种线程安全的集合类他和HashTable也是有区别的主要区别就是加锁的粒度以及如何加锁ConcurrentHashMap的加锁粒度要比HashTable更细一点。将数据分成一段一段的存储然后给每一段数据配一把锁当一个线程占用锁访问其中一个段数据的时候其他段的数据也能被其他线程访问。
#### 八、HashMap 多线程操作导致死循环问题
在多线程下,进行 put 操作会导致 HashMap 死循环,原因在于 HashMap 的扩容 resize()方法。由于扩容是新建一个数组,复制原数据到数组。由于数组下标挂有链表,所以需要复制链表,但是多线程操作有可能导致环形链表。复制链表过程如下:
以下模拟2个线程同时扩容。假设当前 HashMap 的空间为2临界值为1hashcode 分别为 0 和 1在散列地址 0 处有元素 A 和 B这时候要添加元素 CC 经过 hash 运算,得到散列地址为 1这时候由于超过了临界值空间不够需要调用 resize 方法进行扩容,那么在多线程条件下,会出现条件竞争,模拟过程如下:
线程一:读取到当前的 HashMap 情况,在准备扩容时,线程二介入
![输入图片说明](https://images.gitee.com/uploads/images/2018/0902/124903_58cfe293_87650.jpeg "11.jpg")
线程二:读取 HashMap进行扩容
![输入图片说明](https://images.gitee.com/uploads/images/2018/0902/124909_0bb789e7_87650.jpeg "22.jpg")
线程一:继续执行
![输入图片说明](https://images.gitee.com/uploads/images/2018/0902/124915_5a89ac2e_87650.jpeg "33.jpg")
这个过程为,先将 A 复制到新的 hash 表中,然后接着复制 B 到链头A 的前边B.next=A本来 B.next=null到此也就结束了跟线程二一样的过程但是由于线程二扩容的原因将 B.next=A所以这里继续复制A让 A.next=B由此环形链表出现B.next=A; A.next=B
### 推荐阅读: