HashMap解析(JDK1.7和1.8区别)

HashMap解析

1.Hashmap在插入元素过多的时候需要进行Resize,Resize的条件是:

​ HashMap.Size > Capacity * LoadFactor。

2.Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环(头插)。

3.1.8后采用尾插(对树的操作会出现死循环,但不会有链表环),并采用了红黑树(节点>8且table的长度>=64)。

JDK1.8版本之前扩容的死循环、数据丢失问题

以下为1.8之前的扩容代码,e.next = newTable[i];newTable[i] = e;可以看出链表采用的是头插法。

来看下死循环是怎么形成的:

假设遍历链表A -> B -> null,两个线程,遍历元素A,线程1运行完Entry<K,V> next = e.next这句后暂停(那么e:A,e.next:B);

线程2运行,同样遍历A -> B,运行完后,即为:head -> B -> A -> null;

线程1继续运行 e.next = newTable[i];newTable[i] = e;e = next

循环到A:

A -> B

head -> A

形成循环:head -> A -> B -> A -> B …

循环到B:

B -> A

head -> B

形成循环:head -> B -> A -> B …

然后交替循环A、B,死循环了。

/**
 * Transfers all entries from current table to newTable.
 */
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;
        }
    }
}

JDK1.8 HashMap

hash()

h = key.hashCode,h ^ (h>>>16) 用到了 异或 运算。

首先h相等时,hash也是相等的。

当 h < 2^16 时,h >>> 16等于0,而0与h作异或运算,hash = h。

当 h >= 2^16 时,hash肯定不等于h。

static final int hash(Object key) {
   
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

resize()

我们知道HashMap是数组+链表结构 +红黑树,这里只讨论链表。假设初始容量为默认的oldCap = 16。

1.遍历数组桶,如果里面装的链表结构只有一个节点,那么重新分配。

if (e.next == null) ​ newTab[e.hash & (newCap - 1)] = e;

2.如果链表有多个节点,比如A -> B -> C -> null,那么就要把ABC分为 低位链表(loHead、loTail) 和

​ 高位链表(hiHead、hiTail),假设A不动,还是原来桶的位置,而B、C属于高位,那么B->C(这里是尾插)

​ 这个高位链表就会插入到新桶位置为:旧桶位置 + 16(newTab[j + oldCap] = hiHead;ÿ

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值