HashMap持有重复键

时间:2017-02-21 16:02:22

标签: java concurrency hashmap

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

使用0到9999之间的键尝试放入(键,值)4个线程,值为常量字符串。完成所有线程后,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 个答案:

答案 0 :(得分:5)

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

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

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

  

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

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

相关问题