现有数据 {name:“张三”,age:"18",major:"computer",sex:"女"},请创建一个方法名称为:save(HashMap<String,String> map),实现将上述数据存入,并创建对象调用方法。
public class{
public static void main(String[] arg){
//请在此处完成
}
//请在此处创建方法
}
save方法都没有传参,而且设计的有点不合理,没太理解意思
默认HashMap的初始长度是16,比较小,每一次push的时候,都会检查当前容量,如果需要扩容,整个表里的所有元素都需要按照新的hash算法被算一遍,这个代价较大。
ReHash过程:每个元素重新算hash值,将链表翻转(遍历每个bucket上的链表,然后用头插法插入对应的bucket上的链表中)。对于同时准备扩容的两个线程1和2,如下图:
源码如下:
while(null != e) {
Entry<K,V> next = e.next; //线程1还没有执行这句 中断了
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);//计算hash值
}
int i = indexFor(e.hash, newCapacity);//获取扩容后这个结点对应索引位
e.next = newTable[i];//这三行代码表示头插法插入
newTable[i] = e;
e = next;
}
(1)线程1,中断,线程2 reHash
(2)线程2将原表 bucket 1 处的链表分发到 新表 bucket 1 和 bucket 3 上(hash值的后2位,第一位不同,则不是01就是11),分散到 bucket 3上的值有两个, key(3), key(7),遍历原表Bucket 1 上的 链表,采用头插法,结果就是 链表反转且还属于新表此bucket的元素放到 此bucket上。此时 key(7) -> key(3) -> null
(3)此时线程 2 被中断,线程 1调度。
此时线程 1 中 e 是 key(3)-> null,根据源码继续将e插入对应的table[3]链表,头插法,结果为:key(3)->key(7)->key(3),这是一个循环链表。
e = next, e是null,才能跳出循环。上面e永远不会空,死循环了。