HashMap持有重复键

3

在尝试使用HashMap时,我注意到了一些奇怪的事情。

使用4个线程,每个线程都试图插入(key,value),其中key从0到9999,value是一个常量字符串。当所有线程完成后,map.size()返回值大于10,000。这是怎么发生的?这是否意味着map包含重复的键?

我遍历了map.entrySet()并发现某些键的计数确实超过1。如果我在map中为这样的键执行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
如果我执行......会返回什么值?为什么不直接去试试呢? - D M
@DM。我认为测试在运行之间可能无法重复,甚至在给定的运行中也可能如此。 - Mad Physicist
1个回答

6

HashMap不是线程安全的,如链接文档中明确说明的那样。您提供了一个很好的例子,说明这是为什么。是的,您正在放置重复的键,因为put没有检查另一个线程是否正在放置相同的键。这就是不安全的含义。

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

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

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

另一种选择是使用ConcurrentHashMap,它专门为此目的设计。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接