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。并发

相关文章
相关标签/搜索