在尝试时HashMap,我发现有些奇怪。
HashMap
运行4个线程,每个线程尝试使用0到9999之间的键放置(键,值),并给一个常量字符串赋值。完成所有线程后,map.size()返回大于10,000的值。这怎么发生的?这是否意味着地图包含重复的键?
map.size()
我在上进行了迭代map.entrySet(),发现某些键的数量确实大于1。如果我get()在地图上对一个这样的键进行操作,将会返回什么值。
map.entrySet()
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());
HashMap如链接文档中明确指出的那样,它不是线程安全的。您正在提供一个很好的例子说明为什么会这样。是的,您放入重复的密钥是因为put不检查是否有另一个线程正在放入相同的密钥。这就是说不保证线程安全。
put
检索行为是不确定的,因此它可以返回此时所需的任何值。它可能非常依赖于实现,平台,甚至与时序有关。
有几种解决方法。在文档中建议的一个是
Map m = Collections.synchronizedMap(new HashMap(...));
另一个选择是使用ConcurrentHashMap,它是专门为此目的而设计的。
ConcurrentHashMap