线程安全地图操作



我遇到了以下代码,并指出了一些不一致的信息 - 对于多线程安全代码。

    Map<String,Map<String,Set<String>> clusters = new HashMap<.........>;
    Map<String,Set<String>> servers = clusters.get(clusterkey);
    if(servers==null){
      synchronized(clusterkey){
       servers = clusters.get(clusterkey);
       if(servers==null){....initialize new hashmap and put...}
      }
    }
    Set<String> users=servers.get(serverkey);
    if(users==null){
      synchronized(serverkey){
       users=servers.get(serverkey);
       if(users==null){ ... initialize new hashset and put...}
      }
    }
    users.add(userid);
  1. 为什么在clusterkey上同步地图 - 不应该在地图上作为监视器本身?
  2. 不应该最后一个用户。
  3. 这似乎是以线程安全添加单个用户的很多代码。什么是更智能的实现?

在这里只是一些观察:

  1. String上同步是一个非常糟糕的主意 ->在clusterKey上同步,serverKey可能无法按预期的方式工作。
  2. 最好是使用 ConcurrentHashMap s和 ConcurrentHashSet s。

尽管没有更多上下文,但实际上不可能回答这个问题。看来代码作者想安全地每clusterKeyserverKey安全地创建1个映射,因此只能添加一次用户。

a(可能更好)的方法就是在clusters本身上仅synchronize,然后您安全,因为只有一个线程可以读取和/或写入上述地图。

另一种方法是使用自定义Lock s,也许是一个用于阅读的方法,而另一种则用于写作,尽管如果一个线程写入Map,而另一个线程则从中读取该值的确切值,则可能会再次导致不一致。<<<<<<<<<<<<<<<<<<<<<<

代码看起来像是通过双检查锁定习惯的版本进行的,有时用于懒惰初始化。阅读提供的链接,以了解为什么这是一个非常糟糕的实现。

给定代码的问题是它间歇性失败。当有几个线程尝试使用相同的密钥(或具有相同哈希码的键)上工作的几个线程时,就会有种族条件,这意味着首先创建的地图可能被第二个hashmap替换。

1-同步试图避免在该地图中创建一个新条目。第二个必须等待,以便他的(servers==null)也无法返回true

2- users列表似乎不超出范围,但似乎不需要同步。也许程序员知道没有重复的用户ID,或者他不在乎一次又一次地重置同一用户。

3-可能?

最新更新