栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

hashMap产生的循环依赖问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

hashMap产生的循环依赖问题

hashMap是线程不安全的,主要重点讲一下,线程不安全导致的循环依赖问题 假设:hashMap的数组加链表,数组初始长度为2,同时hash的计算方式为key值%2,同时等到链表长度为3的时候开始扩容,扩容方式为原始数组大小*2,此时两个线程对同一个HashMap进行操作

1.这个是初始状态,同时map里面存储的值

2.此时第一个线程开始进行操作,执行到这一步的时候cup去执行其它线程,导致该线程被挂起
 do {
  Entry next = e.next; // <--假设线程一执行到这里就被调度挂起了,执行其他操作
  int i = indexFor(e.hash, newCapacity);
  e.next = newTable[i];
  newTable[i] = e;
  e = next;
 } while (e != null);

 此时线程1的情况,此时线程扩容然后在准备开始给节点重新分配对应的数组的时候被挂起(这个e和next不懂得可以去了解下链表,e代表当前节点,next代表当前节点中存储的下一个节点的地址)

 

 3.当线程1被挂起的时候线程2刚好访问该集合并且完成了扩容操作

 

 这里讲下为什么扩容成这样,因为链表是从第一个节点开始读的所以一开始处理的应该是key=7,然后key=7被存储到数组3的位置,然后遍历到下一个节点key=3,把3存储到数组3的位置,key=7的前面,为什么存储在前面?因为不用遍历到末尾,这样快。然后在处理key=9。

4.同时e还是线程1当前所在节点,然后next是它所指向的下一个节点,此时线程1恢复执行。

重点来了!!

第一步,线程1会把自己所在的当前节点(e-)进行计算,存储到数组三的位置上去,

 第二步,会遍历到下一个节点,即 (next-),同时把next指向下一个节点(提前获取地址主要是防止链表数据丢失),此时节点e变成(e),而因为线程2的操作,导致e的下一个节点是(next

 

 第三步,此时会把e插入,同时节点向下遍历(同2)

 第四步,会把e节点插入到数组三,应为next指向的是null到尽头了,所以就不需要向下遍历了

         于是一个环形链表就形成了,因为key=7的下一个节点是指向key=3的,但是key=3的节点又指向着key=7.

        这样就是一个很经典hashMap线程不安全导致的循环依赖,因为是个循环链表,就会导致数组一直重复扩容,导致集合的一个无限大,但是JDK1.8的时候引进了红黑树,当连续扩容32次的时候会转换成红黑树,解决这个循环依赖的问题。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/678497.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号