java - HashMap 持有重复键

标签 java concurrency hashmap

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

运行 4 个线程,每个线程都尝试将 (key,value) 与从 0 到 9999 的键放在一起,值是一个常量字符串。所有线程完成后,map.size()返回的值大于 10,000。这怎么发生的?这是否意味着 map 包含重复键?

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

这是我试过的代码

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

最佳答案

HashMap不是线程安全的,如链接文档中明确指出的那样。您提供了一个很好的例子来说明为什么会这样。是的,您正在放入重复的 key ,因为 put 不会检查另一个线程是否正在放入相同的 key 。这就是线程不安全的意思。

检索行为是未定义的,所以它可以在那个时候返回它想要的任何值。它可能非常依赖于实现、平台甚至时间。

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

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

另一种选择是使用 ConcurrentHashMap ,这是明确为此目的而设计的。

关于java - HashMap 持有重复键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42372211/

相关文章:

java - 我可以直接将目录从一个地方复制到另一个地方吗?

java - 具有自己的数据类型的 map (Java)

java - 从 hashmap 对象中删除值的有效方法

java - LinkedHashMap 的实例

java - adb连接错误:EOF (new in android )

java - 将嵌套的 Json 发布到 spring Controller

java - 我们应该在连接工厂上调用 setClientId() 吗?

concurrency - 没有 deref 就无法实现副作用

c# - 是什么阻止我的事件处理程序方法完成?

swift - 从其共享实例访问全局参与者属性