当前位置: 代码迷 >> java >> 线程安全映射操作
  详细解决方案

线程安全映射操作

热度:129   发布时间:2023-07-31 13:46:00.0

我遇到了以下代码,并指出了一些不一致之处-多线程安全代码。

    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. 最后的users.add ...是否也应该同步?
  3. 以线程安全的方式添加单个用户似乎是很多代码。什么是更聪明的实现?

这里只是一些观察结果:

  1. ->在clusterKeyserverKeyclusterKey同步可能无法达到预期的效果。
  2. 最好使用ConcurrentHashMapConcurrentHashSet

尽管没有更多背景信息,但实际上不可能回答这个问题。 似乎代码编写者希望安全地为每个clusterKeyserverKey创建1个映射,以便仅可以一次添加用户。

一种(可能更好)的方法是仅在clusters映射本身上进行synchronize ,因此您很安全,因为只有一个线程可以读取和/或写入该映射。

另一种方法是使用自定义Lock ,可能一个用于读取,另一个用于写入,尽管如果一个线程正在向Map写入而另一个线程正在从Map中读取该确切值,则这可能再次导致不一致。

该代码看起来像是的非完整版本,有时用于惰性初始化。 阅读提供的链接,了解为什么这是一个非常糟糕的实现。

给定代码的问题是它间歇性地失败。 当有多个线程试图使用相同的键(或具有相同哈希码的键)在地图上工作时,存在竞争状态,这意味着第一个创建的地图可能会被第二个哈希图替换。

1-同步试图避免两个线程同时在该Map中创建新的Entry。 第二个必须等待,这样他的(servers==null)也不会返回true

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

3- 也许吗?

  相关解决方案