问题
While experimenting with HashMap, I noticed something weird.
Ran 4 threads with each trying to put (key,value) with keys from 0 to 9999, value a constant string. After all threads were done, map.size() returned a value greater than 10,000. How did this happen? Does this mean that the map contains duplicate keys?
I iterated on the map.entrySet() and found that the count for some keys were indeed more than 1. What value would be returned if I do a get() on the map for one such key.
Here is the code that I tried
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 is not thread safe, as explicitly noted in the linked docs. You are providing a good example of why this is so. Yes, you are putting in duplicate keys because put does not check that another thread is putting the same key in. That is what it means not to be thread safe.
The retrieval behavior is undefined, so it can return whichever value it wants at that point. It is probably very implementation, platform and even timing-dependent.
There are a couple of workarounds. The one suggested in the docs is
Map m = Collections.synchronizedMap(new HashMap(...));
Another option is to use ConcurrentHashMap, which is explicitly designed for the purpose.
来源:https://stackoverflow.com/questions/42372211/hashmap-holding-duplicate-keys