扩展的HashMap 和同步只穿(Extending HashMap and synch

2019-09-22 10:46发布

我最近遇到了一个扩展HashMap和同步put方法我们的代码库的类。

除了它比使用ConcurrentHashMap的效率较低,可以延伸HashMap和同步容下(K,V)出现什么样的问题?

假设我们不关心是否可以得到(K)返回的最新值或没有(如我们罚款线程互相覆盖并且如果使用的地图的值,我们不关心可能出现的可能的竞争条件为锁定自己)。

例:

public class MyMap<K,V> extends HashMap<K,V> {
  //...
   public synchronized void put(K key, V value) {
      //...
   }

  //...
}

据我所知,HashMap中做了重新的大小与put方法和自投放在地图实例级同步,同时重新上浆过程中遇到的问题,将(可能)不会遇到。

即使有上述问题的假设,我的直觉,感觉告诉我,有可能出现更多的问题。 或者,我只是被偏执?

更新:谢谢大家,这是乐趣和启发。 如果我见到这个特定类的作者原来的,我现在可以解释他的详细愚蠢。 :)

总结:的putAll仍然可以弄糟数据结构可怕和可怕的无限循环/数据争用条件结束。 得到依赖于哈希映射的可能处于被修改同时使的get过程的行为古怪的过程中底层的内部数据结构。 这仅仅是一个普遍糟糕的主意。 最起码,笔者也可以使用Collections.synchronizedMap(地图)代替。

注:鉴于在写这篇文章的所有三个答案其实是正确的,但我选择了一个大约的get()为正确答案,因为这是最不明显的一个我。

Answer 1:

因为get()可以读取变化的数据结构,一切不好的可能发生。

我见过的get()陷入死循环,所以它不只是一个理论上的可能性,不好的事情发生。



Answer 2:

我希望你也同步上putAllremoveputAll特别是由于多个线程可以尝试和调整你的HashMap中。 这些方法也将被更新sizemodCount这要是同步之外进行可能导致丢失更新。



Answer 3:

正如我在评论中所提到的,可能出现的另一个问题是, putAll(Map)方法似乎并不同步。 由于putAll还可以修改地图的结构,它是不安全的,而另一个线程正在使用相同的地图调用它从一个线程同步。

在更高的层次,虽然,它很有趣,了解更多的为什么 ,为什么周围put(key, value)进行synchronized 。 即使你现在防范的不同步修改地图的结构,它仍然似乎并不像多线程访问该地图不同步是个好主意。 事实上,如果线程A试图遍历HashMap中的内容,而线程B调用synchronized put(key, value) ,在线程A的迭代器仍然会失败快速抛出ConcurrentModificationException ,而不是做一些不确定性。

即使你到同步putAll(Map)调用,其他线程遍历地图的内容仍然会看到异常。 如果地图需要多个线程使用,这些线程中的至少一个需要修改的地图,所有的呼叫需要同步,期。



文章来源: Extending HashMap and synchronizing only puts