美文网首页
为什么HashMap是线程不安全的

为什么HashMap是线程不安全的

作者: 猴子请来的逗比_f099 | 来源:发表于2019-05-14 17:40 被阅读0次

    主要是同一个hashmap在多线程情况下执行扩容方法后,再去调用Get方法可能会发生死循环的。

    首先:

    链表的next只是引用。保存的是引用指向的地址。所以多线程情况下可能会出现其他线程改变了next指向的目标后,当前线程继续执行。

    读取时发生死循环的原因:

    正常的 a->b->c 变成了a->b 而且 b->a。

    发生的具体情况的例子如下:

    前提:两个线程同时调用一个hashMap的扩容方法。
    0.原先的hashmap链是 a->b->c
    1.线程1 执行(Entry<K,V> next = e.next;)后。读取了a 和a.next=b之后 线程时间片用完,调用线程2
    2.线程2 完整的执行整个rehash操作,使hashmap得链变成了c->b->a(jdk1.7中hashmap的rehash用的是头插法)
    3.继续执行线程1 的循环操作
    第一次循环:线程1中的newTable变成了a->null
    第二次循环:线程1中的newTable变成了b->a
    第三次循环:线程1中的newTable变成了a->b->a

    具体代码的执行情况如下:

    线程1 第一次循环

    while(null != e) {
        Entry<K,V> next = e.next;// next指向b
        int i = indexFor(e.hash, newCapacity); 
        e.next = newTable[i]; //  e.next = null
        newTable[i] = e;//  newTable[i] =a  所以  newTable的链是 a->null
        e = next;// 把e指向b
    }
    

    线程1 第二次循环

    while(null != e) {
        Entry<K,V> next = e.next;// e是b    next指向a(由于线程2已经执行完毕,已经把b的next指向了a)
        int i = indexFor(e.hash, newCapacity); 
        e.next = newTable[i];// e.next = a  
        newTable[i] = e;//  这里相当于把newtable的链从a->null变成b->a
        e = next; //把e指向 a
    }
    

    线程1 第三次循环

    while(null != e) {
        Entry<K,V> next = e.next;// e是a    next指向null
        int i = indexFor(e.hash, newCapacity); 
        e.next = newTable[i];// e.next = (b->a)    所以e指向的是:a->(b->a)//这里形成了死循环
        newTable[i] = e;//  这里相当于把newtable的链从b->a 变成了a->(b->a)
        e = next; //把e指向 null 退出循环
    }
    

    相关文章

      网友评论

          本文标题:为什么HashMap是线程不安全的

          本文链接:https://www.haomeiwen.com/subject/oojeaqtx.html