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出现了环形链表...

 

posted @ 2018-07-02 01:03  KristinLee  阅读(1770)  评论(1编辑  收藏  举报
jQuery火箭图标返回顶部代码