HashMap死循环核心代码模拟

https://www.jianshu.com/p/1e9cf0ac07f4

应用中碰到使用linkedhashmap出现了循环指向导致的线程遍历死循环的问题,linkedhashmap继承自hashmap,从网上查询了一下相关的文章,大都说的比较一致。 但是个人感觉抽象理解起来比较困难,虽然介绍已经非常详细了,遂自己总结了一下

大概的逻辑如下,详细的可以看上面的链接。

 

死循环现象主要出现在多线程并发使用hashmap进行put操作时。

多线程在put时都进入到put方法,并且由于hashmap内部自身entry数量不够需要进行扩容,在扩容的核心方法transform主要是对于new newEntry[oldEntrySize*2]; 然后将旧Entry数组中的链表数据rehash获取新的new_hash_index放入到新的entry中。

由于旧entry[]数组中的每个元素的值是一个链表的头指针,并不是单个元素。需要遍历每个指向的元素重新计算hash值并放入到新的entry[hash_index]中,当同一个链表中的元素重新计算hash后的数组下标仍然相同时,hashmap扩容后会出现在旧entry[i]链表中的链表方向与新扩容后链表的方向相反。

这是由于线程需要遍历每个链表中的元素重新计算hash值,因此会导致原来的链表头在新链表中变成链尾,原来的尾部元素在新链表中变成头指针并被保存在newEntry[hash_index]中。

而正是由于遍历过程中链头链尾反转链接的操作过程,导致在多线程执行环境下容易产生环链,最终查询时出现死循环。

 

自己把hashmap扩容方法transform核心代码摘取下来模拟了一下环链过程。并画了一个二维表执行过程,从开始到结束两个线程是如何形成环链的,加深自己的理解。

class LinkEntry {

       char value;

      LinkEntry next;

       LinkEntry(char value, LinkEntry next) {

       this.value = value;

       this.next = next;

}

}

 

static LinkEntry reverse(LinkEntry entry) {

       LinkEntry head = null;

       LinkEntry next = null;

 

LinkEntry tmp = entry;

       while (tmp != null) {

              next = tmp.next;

              tmp.next = head;

              head = tmp;

              tmp = next;

}

}

 

测试数据集结构

a->b->c

 

核心流程

代码

tmp

next

head

 

tmp

next

head

while (tmp != null)

a->b->c

null

null

a->b->c

null

null</

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值