2017-02-21 28 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,这是明确设计为宗旨。