多线程访问HashpMap产生死锁原因

来源:互联网 发布:知乎wifi刷不出来图片 编辑:程序博客网 时间:2024/06/08 07:08

通过源码知道:HashMap的基本数据结构是Entry[] table。每个entry=table[i]都有next属性,它其实只指向和entry有相同hash值的下一个对象,也就是同一个桶中的下一个数据。

HashMap这个数据结构不是线程安全的,几乎所有人都知道。当我们采用多线程进行读写的时候必然会存在线程同步的问题。那怎么会产生死锁呢?我来贴下源代码。

 void resize(int newCapacity) {        Entry[] oldTable = table;        int oldCapacity = oldTable.length;        if (oldCapacity == MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;            return;        }        Entry[] newTable = new Entry[newCapacity];        transfer(newTable);        table = newTable;        threshold = (int)(newCapacity * loadFactor);    }    /**     * Transfers all entries from current table to newTable.     */    void transfer(Entry[] newTable) {        Entry[] src = table;        int newCapacity = newTable.length;        for (int j = 0; j < src.length; j++) {            Entry<K,V> e = src[j];            if (e != null) {                src[j] = null;                do {                    Entry<K,V> next = e.next;                    int i = indexFor(e.hash, newCapacity);                    e.next = newTable[i];                    newTable[i] = e;                    e = next;                } while (e != null);            }        }    }

resize函数是发生在容量不够的情况下的。当申请完了新的内存空间后,我们要把原来的内存空间中的数据转移到新内存空间中去。也就是transfer函数。

假设现在有三个线程:T1,T2,T3;在老数组中的第一个数据也就是e引用的对象,我们称它为A,在新数组中的头两个数据分别为B和C,B.next=C。

 

线程T1运行到e.next=newTable[i]时线程T2运行到next=e.next;然后线程t1去继续

运行,会产生什么效果呢?A.next=B,B.next=C。e指向的对象是B,newTable[i]=A。然后继续运行,e.next=newTable[i],也就是B.next=A;同时A.next=B,继续运行newTable[i] = e,e = next;如果没有其它线程捣乱的话,那么此时e应该是C啊,可惜只是如果,如果有第三个线程T3在线程T1执行e.next = newTable[i]的时候去执行next = e.next;那么就中途改变了next的值,本来是保存C的,但是现在成了A了。总结下现在的情况:e引用A,nextTable[i]引用B,A.next=B,B.next=A。现在明白了吧。会一直这么死锁下去的。

0 0
原创粉丝点击