您的位置:首页 > 编程语言 > Java开发

HashMap环 JDK1.7

2017-12-04 21:06 141 查看
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);
}

/**
*  构造新数组
*/
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];// e为原数组中的元素
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);
}
}
}


输入5,7,3,形成如下:



正常扩容之后:



链表环

现存在两个线程A和B,当A执行到

Entry<K,V> next = e.next;


时,CPU切换到B,执行了扩容,并且扩充完毕,如上图,正常扩容之后的图。

此时CPU再切换到A,执行如下:

Entry<K,V> next = e.next;// e=3,next=7
e.next = newTable[i];// e.next=null
newTable[i] = e; // newTable[i]=3
e = next;// e=7




再往下执行:

Entry<K,V> next = e.next;// e=7,next=3(参照B扩容后的链表)
e.next = newTable[i];// e.next=3
newTable[i] = e; // newTable[i]=7
e = next;// e=3




再往下执行:

Entry<K,V> next = e.next;// e=3,next=null(参照B扩容后的链表)
e.next = newTable[i];// e.next=7
newTable[i] = e; // newTable[i]=3
e = next;// e=null




即3的next是7,7的next是3,由此形成环,在查询的时候,会陷入“死循环”。

最后插入5,放在第二个,没有影响。

元素丢失

输入3,5,7,行程如下:



按照以上思路分析,不难得出结论,元素3最后会丢失。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java容器 并发