HashMap的死循環

  1. 併發的HashMap爲何會引發死循環?
  • 在多線程使用場景中,應該儘可能避免使用線程不安全的 HashMap,而使用線程安全的 ConcurrentHashMap。那麼爲何說 HashMap 是線程不安全的,下面舉例子說明在併發的多線程使用場景中使用 HashMap 可能形成死循環。代碼例子以下(便於理解,仍然使用 JDK1.7 的環境):java

    public class HashMapInfiniteLoop {  
    
        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();        
        }  
    }複製代碼

    其中,map初始化爲一個長度爲2的數組,loadFactor=0.75,threshold=2*0.75=1,也就是說當put第二個key的時候,map就須要進行resize。git

    經過設置斷點讓線程1和線程2同時debug到transfer方法(3.3小節代碼塊)的首行。注意此時兩個線程已經成功添加數據。放開thread1的斷點至transfer方法的「Entry next = e.next;」 這一行;而後放開線程2的的斷點,讓線程2進行resize。結果以下圖。github

    img

    注意,Thread1的 e 指向了key(3),而next指向了key(7),其在線程二rehash後,指向了線程二重組後的鏈表。數組

    線程一被調度回來執行,先是執行 newTalbe[i] = e, 而後是e = next,致使了e指向了key(7),而下一次循環的next = e.next致使了next指向了key(3)。安全

    img

    img

    e.next = newTable[i] 致使 key(3).next 指向了 key(7)。注意:此時的key(7).next 已經指向了key(3), 環形鏈表就這樣出現了。多線程

    img

    因而,當咱們用線程一調用map.get(11)時,悲劇就出現了——Infinite Loop。併發

相關文章
相關標籤/搜索