【发布时间】:2012-09-14 18:26:41
【问题描述】:
我最近在我们的代码库中遇到了一个类,它扩展了 HashMap 并同步了 put 方法。
除了比使用 ConcurrentHashMap 效率低之外,扩展 HashMap 并仅同步 put(K,V) 可能会出现哪些问题?
假设我们不关心 get(K) 是否返回最新值(例如,我们可以很好地处理线程相互覆盖,并且我们不关心如果地图本身用作锁)。
例子:
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() 的一个作为正确答案,因为它对我来说是最不明显的一个。
【问题讨论】:
-
但是哈希表是这样同步的。
-
哈希表完全同步(放置和获取)。
-
所以,同步获取会让它变得更慢
-
是的,哈希表已经同步了 put 和 get ,所以它被锁定了。它很慢,但它是线程安全的。
-
源代码中是否有任何迹象表明同步
put(key, value)方法的目标是什么?如果是为了避免两个线程同时在结构上修改map而不同步所有操作,那么又错过了一次写操作——putAll(Map)
标签: java concurrency synchronization