HashMap持有重复键

在尝试使用HashMap ,我发现了一些奇怪的东西。

运行4个线程,每个线程尝试使用0到9999之间的键(键,值),值为常量字符串。 完成所有线程后, map.size()返回大于10,000的值。 这怎么发生的? 这是否意味着地图包含重复的键?

我迭代了map.entrySet()并发现某些键的计数确实超过1.如果我在地图上为一个这样的键执行get() ,将返回什么值。

这是我试过的代码

 final HashMap 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()); 

HashMap不是线程安全的,如链接文档中明确指出的那样。 你提供了一个很好的例子,说明为什么会这样。 是的,你输入了重复的密钥,因为put没有检查另一个线程是否放入相同的密钥。这就是说它不是线程安全的。

检索行为是未定义的,因此它可以返回它在该点所需的任何值。 它可能是非常实现,平台甚至是时间依赖的。

有几种解决方法。 文档中建议的那个是

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

另一个选择是使用ConcurrentHashMap ,它是为此目的明确设计的。