JDK1.7 HashMap死循環問題


為什么說HashMap線程不安全呢?

因為並發情況下,HashMap可能造成死循環...

在多線程使用場景中應該盡量避免使用線程不安全的HashMap,可以使用ConcurrentHashMap或者Collections.synchronizedMap().

map初始化為一個長度為2的數組,loadFactor=0.75,threshold=2*0.75=1,所以當put第二個key的時候map就需要resize,然后執行transfer方法,將舊元素進行rehash

下面是transfer方法

void transfer(Entry[] newTable, boolean rehash) {
	int newCapacity = newTable.length;
	for (Entry<K,V> e : table) {
		while(null != e) {	   
			Entry<K,V> next = e.next;  //(1)		
			if (rehash) {			
				e.hash = null == e.key ? 0 : hash(e.key);	   
			}		
			int i = indexFor(e.hash, newCapacity);		
			e.next = newTable[i];	    //(2)	
			newTable[i] = e;	    //(3)	
			e = next;	            //(4)
		}
	}
}

執行以下測試方法

public class DailyTest {
    private static HashMap<Integer, String> map = new HashMap<Integer, String>(2, 0.75f);

    public static void main(String[] args) {
        map.put(5, "C");
        new Thread("Thread1") {
            public void run() {
                map.put(7, "B");
                System.out.println(map);
            }
        }.start();

        new Thread("Thread2") {
            public void run() {
                map.put(3, "A");
                System.out.println(map);
            }
        }.start();
    }
}  

正常執行過程

並發執行過程

通過設置斷點讓Thread1和Thread2同時Debug到transfer方法的首行,注意此時兩個線程已經成功添加數據,放開Thread1的斷點至transfer方法的Entry next=e.next;這一行,然后放開Thread2的斷點,讓Thread2進行resize

之后Thread1被被調度回來繼續執行后面代碼

至此,HashMap出現了環形鏈表...

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM