我最近在我们的代码库中遇到了一个类,它扩展了 HashMap 并同步了 put 方法。
除了它比使用 ConcurrentHashMap 效率低之外,扩展 HashMap 并仅同步 put(K,V) 可能会出现什么样的问题?
假设我们不关心 get(K) 是否返回最新值(例如,我们可以很好地处理线程相互覆盖,并且我们不关心使用 map 的值时可能出现的竞争条件作为锁本身)。
例子:
public class MyMap<K,V> extends HashMap<K,V> {
//...
public synchronized void put(K key, V value) {
//...
}
//...
}
据我所知,HashMap 使用 put 方法重新调整大小,并且由于 put 在 map 实例级别同步,因此(可能)不会遇到并发调整大小期间遇到的问题。
即使有上述有问题的假设,我的直觉告诉我可能会出现更多问题。还是我只是偏执?
更新:谢谢大家,这很有趣,很有启发性。如果我遇到过这门课的原作者,我现在可以详细解释他的愚蠢。:)
总而言之:putAll 仍然会严重破坏数据结构并最终陷入可怕的无限循环/数据竞争状态。get 依赖于 hashmap 的底层内部数据结构,该结构可能正在同时被修改,从而导致 get 过程行为异常。这只是一个普遍的坏主意。至少,作者可以使用 Collections.synchronizedMap(Map) 代替。
注意:撰写本文时给出的所有三个答案实际上都是正确的,但我选择了关于 get() 的一个作为正确答案,因为它对我来说是最不明显的一个。