JDK1.7 HashMap形成闭环链表原因

导读:

        在JDK1.7中,HashMap是一个由链表和数组组成的数据结构。当HashMap元素大于 数组长度*负载因子 时,HashMap会进行扩容,扩容大小为原大小2倍。

void addEntry(int hash, K key, V value, int bucketIndex) {
    if ((size >= threshold) && (null != table[bucketIndex])) {
         resize(2 * table.length);
         hash = (null != key) ? hash(key) : 0;
         bucketIndex = indexFor(hash, table.length);
     }

    createEntry(hash, key, value, bucketIndex);
}

环形链表的形成分析:

进入resize(2 * table.length),找到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;
            }
        }
    }

根据上述代码看,扩容时链表元素顺序会翻转

                A -> B -> null   扩容后   B -> A -> null

假定HashMap中 table[0] 中有元素   

某一刻两个线程( T1,  T2)同时操作该hashMap时,同时需要扩容。假设扩容时A和B的

h & (length-1)  仍相同。

当线程T1进入transfer方法, 第一次执行到 第5行时   这时记录 next=B ,  e=A。线程T1挂起。

线程T2进入方法并执行完成,这时HashMap的 table[0] 链表被T2修改为

线程T1重新开始执行, 对线程T1来说, next还是B, A.next = newTable[0] = null, 然后A被放入链表头, 链表变为A -> null;

T1再次进入循环,  e = B, 因为 B.next 被 T2线程 修改为A,  next = A,     B.next = newTable[0] = A, 然后B被放入链表头, 链表变成:

正常的话现在应该退出循环,因为B.next被设置为A,再次进入循环。

e = A,  next = null, 将A设置到链表头,A.next设置为 为newTble[0] 即 B, 将A放入链表头, 所以形成了闭环 A -> B -> A。

T1的e为null,正常退出不报错。

当执行get的时候,因为要遍历链表,进入死循环。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值