JDK1.7HashMap链表死循环分析

HashMap 执行 put 操作的大致流程

1、put操作;
2、调用addEntry()方法;
3、查看是否需要扩容 -> 是 ;
4、调用扩容方法resize(2 * table*length);
5、扩容后 将扩容前的数据转移到新的table里 transfer();
6、如果需要重新hash,则重新计算hash值,并重新计算数组下标;
7、扩容后插入新值。

transfer方法

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;
            }
        }
    }

其中table 表示未扩容前的数组

transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;

例当前有两个线程T1、T2

1、当前HashMap中数组里有数据为 table1 -> (5, ‘A’) ->(9, ‘B’) -> null
2、T1、T2 同时调用put操作
3、T1 执行到transfer的 Entry<K,V> next = e.next
4、T1 记录到next = (9,‘B’),e = (5,‘A’),线程挂起
5、T2执行完后 由于采用的是头节点插入的方式,所以执行完后链表信息 (9, ‘B’) ->(5, ‘A’)-> null
6、此时唤醒T1线程
7、继续执行 由于key相同所以T1、T2两者肯定是在同一桶内
8、插入节点 1(5,‘A’)-> null,此时e为(9,‘B’)
9、 继续插入节点2 (9,‘B’)-> (5,‘A’)-> null
10、有第5步知T2线程执行后 (9,‘B’)节点后还有个(5,‘A’)节点,之后才为null节点
11、所以T1 里此时 e 为(5,‘A’)节点
12、根据e.next = newTable[i];得(5,‘A’)->(9,‘B’)
13、所以此时为(9,‘B’)<=> (5,‘A’)-> null
14、由于next为null所以此时结束,出现了链表循环

链表循环导致的问题

如果此时get 5或者9时,可以正常查找到值,但是如果get一个值也在5,9的桶里,会导致一直找节点的next节点,导致死循环。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值