1. 程式人生 > >HashMap死迴圈記錄

HashMap死迴圈記錄

0.jdk1.7

1.檢視HashMap的原始碼,瞭解其結構和實現原理

2.單執行緒的時候,不會造成死迴圈

3.多執行緒的時候,當兩個執行緒都在擴容的時候,一個 執行緒掛起,另一個已經完成,掛起的那個在擴容的時候會和第二個執行緒的資料死迴圈

4.死迴圈,原因。可能主主存和快取的運營。每個執行緒都有自己的快取,entry的e和next指標都在快取裡。當一個執行緒完成擴容,entry的順序已經倒置,因為順序變了,就重新整理了主存的順序。當第二掛起的執行緒,在執行的時候,先恢復掛起的順序,當執行完正常的流程的時候,它回去主存裡取資料,主存裡的順序是執行緒一修改的,兩個執行緒順序互相指向對方,死迴圈開始。

5.執行緒1和執行緒2執行以下程式碼 map裡裡面的是三個數3,7,5,初始個數是2,當3個就會擴容,執行以下程式碼

 

1.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;

執行緒1停到了1的地方,map的順序還是3->7->5  自己的newTable為空

執行緒2開始執行,map的順序反轉變成   5-null;自己的newTable已賦值,並且把newTable的值賦給table。

                                                              7->3->null;

這時候執行緒一開始執行

迴圈一次:

當前e=3

next=3.next=7;因為停到了這裡,所以執行緒一去到的數字順序還是之前的順序,其實已經被執行緒2改變了。

3.next=newTable[i]=null

newTable[i]=3;

e=next=7;

迴圈二次:

當前e=7

next=7.next=3;這時候取值是是從執行緒2改變的map裡取值的,這裡取得值已經是改變了的table,所以7的下next指向了3

7.next=newTable[i]=3;因為上一步已經把3放進去了

newTable[i]=7;把7也放進去了

e=next=3;

迴圈三次:

當前e=3

next=3.next=null;還是執行緒2 的順序了;

3.next=newTable[i]=7;

newTable[i]=3;

e=next=null;

e=null,迴圈停止;但迴圈2和迴圈3的時候,綠色文字,3和7已經成為閉環了。

總結:一個執行緒在記錄順序的地方停了,而另一執行緒卻把這個順序反反轉了,當停止的執行緒再次執行的時候,本來該指向下游的指標,指向了上游,就成了閉環,形成了死迴圈。