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
,它是为此目的明确设计的。