zoukankan      html  css  js  c++  java
  • 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出现了环形链表...

  • 相关阅读:
    送股分红是怎么回事?
    基金申购费用计算
    msn 爬楼梯
    沪市证券交易费用
    OS X
    见到郎咸平:)
    Long long time_Blog更新了
    生~气:)
    突然想起去年的今天
    久久沉思以后
  • 原文地址:https://www.cnblogs.com/Hangtutu/p/9251999.html
Copyright © 2011-2022 走看看