2017-02-21 62 views
1

在試驗HashMap時,我注意到一些奇怪的東西。HashMap持有重複鍵

Ran 4個線程,每個嘗試將鍵(鍵,值)的鍵從0到9999,值爲一個常量字符串。所有線程完成後,map.size()返回的值大於10,000。這怎麼發生的?這是否意味着地圖包含重複鍵?

我迭代了map.entrySet(),發現某些鍵的計數確實大於1.如果我在地圖上爲一個這樣的鍵做了get(),那麼返回什麼值。

這裏是我試過

final HashMap<String, String> vals = new HashMap<>(16_383); 
Runnable task = new Runnable() { 
    @Override 
    public void run() { 
     for (int i = 0; i < 10000; i++) { 
      vals.put(""+i, Thread.currentThread().getName()); 
     } 
    } 
}; 
Thread thread = new Thread(task, "a"); 
Thread thread1 = new Thread(task, "b"); 
Thread thread2 = new Thread(task, "c"); 
Thread thread3 = new Thread(task, "d"); 
thread.start(); 
thread1.start(); 
thread2.start(); 
thread3.start(); 
thread.join(); 
thread1.join(); 
thread2.join(); 
thread3.join(); 
System.out.println(Thread.currentThread().getName() + "vals "+ vals.size()); 
System.out.println(Thread.currentThread().getName() + "vals "+ vals.entrySet().size()); 
System.out.println(Thread.currentThread().getName() + "vals "+ vals.keySet().size()); 
+1

HashMap不是線程安全的。 – Arqan

+0

「如果我這樣做會返回什麼價值......」爲什麼不直接去看看? –

+0

@DM。我認爲測試不會在兩次運行之間重複,甚至可能在一次運行中都不會發生。 –

回答

5

HashMap是不是線程安全的代碼,在鏈接的文檔中明確指出。你提供了一個很好的例子,說明這是爲什麼。是的,你輸入了重複的密鑰,因爲put不檢查另一個線程是否放入了相同的密鑰。這意味着不是線程安全的。

檢索行爲是未定義的,所以它可以返回當前想要的值。這可能是非常實用的,平臺的,甚至是與時間有關的。

有幾個解決方法。一個在文檔中建議是

Map m = Collections.synchronizedMap(new HashMap(...));

另一種選擇是使用ConcurrentHashMap,這是明確設計爲宗旨。