【问题标题】:Collections.newSetFromMap(»ConcurrentHashMap«) vs. Collections.synchronizedSet(»HashSet«)Collections.newSetFromMap(»ConcurrentHashMap«) 与 Collections.synchronizedSet(»HashSet«)
【发布时间】:2023-04-11 06:49:01
【问题描述】:

显然,有两种方法可以使用 Java 的 Collections 实用程序类来获取 thread-safe HashSet 实例。

我问:

  • 它们有何不同?
  • 哪个以及在什么情况下比另一个更受欢迎?

【问题讨论】:

    标签: java collections concurrency thread-safety hashset


    【解决方案1】:

    你可能想到的是

    Set<Type> set = Collections.newSetFromMap(new ConcurrentHashMap<Type, Boolean>());
    

    这支持并发更新和读取。它的迭代器不会抛出 ConcurrentModicationException。在哪里

    Set<Type> set = Collections.synchronizedSet(new HashSet<Type());
    

    重量更轻,但一次只允许一个线程访问集合。如果您想对其进行迭代,则需要显式锁定该集合,如果您不以安全的方式更新它(在迭代时),您仍然可以获得 CME

    【讨论】:

    • 我认为你应该改写“只允许一个线程读取或写入”。
    【解决方案2】:

    第一个返回的 Set 基本上具有与作为参数传递的映射相同的线程安全和性能保证。如果映射不是线程安全的,那么集合也不会是线程安全的。您通常使用此方法从并发映射创建并发集,因为 API 中没有 ConcurrentHashSet。

    第二个返回给定集合的代理,它的所有方法都同步。

    【讨论】:

      【解决方案3】:

      实际上你可能会得到几个 Set 线程安全的实现。

      我。 Collections.synchronizedSet(new HashSet

      我不会推荐这个解决方案。它本身是线程安全的,在并发环境中仍然必须小心使用。见:

      Stack stack = new SynchronizedArrayStack(new ArrayStack());
      ...
      // don't do this in a multi-threaded environment
      if (!stack.isEmpty()) {
        stack.pop();              // can throw IllegalStateException
      }
      

      因此您必须使用客户端锁定:

      synchronized(stack) {
        if (!stack.isEmpty()) {
          stack.pop();
        }
      }
      

      二。 Set 接口的第二种可选并发实现 - CopyOnWriteArraySet。但是,此解决方案不应在您期望进行多次搜索或插入的环境中使用。但是每个元素的迭代成本比 HashSet 快 O(1),而且它有一个优势,在某些应用程序中非常引人注目。

      三。最后一个使用CuncurrentHashMap的实现:

      Collections.newSetFromMap(new ConcurrentHashMap<Type, Boolean>());
      

      它使用 java.util.concurrent.locks.Lock 的实现。映射将自身划分为可以单独锁定的部分,从而提高了并发性。所以你应该在最后两个选项之间做出选择。

      Thera 也是有序集合实现的选项。我建议您阅读Java Generics and Collections 章节11.5 Collections and Thread Safety

      【讨论】:

        【解决方案4】:

        Collections API 将地图的构建留给客户端,如下所示:

        ConcurrentHashMap<String, Boolean> conMap = new   ConcurrentHashMap<String, Boolean>();
        Set<String> users = Collections.newSetFromMap(conMap);
        System.out.println("Users: " + users);
        users.add("Jon");//results in adding to the conMap instance
        users.add("Tyron");
        System.out.println("Users: " + users);
        System.out.println("conMap = " + conMap);
        

        添加到集合也添加到地图

        用户:[泰伦,乔恩] conMap = {Tyron=true, Jon=true}

        conMap.put("Jubin", Boolean.FALSE);
        System.out.println("Users: " + users);
        System.out.println("conMap = " + conMap);
        

        添加到地图也会导致添加到集合中

        用户:[Tyron、Jubin、Jon] conMap = {Tyron=true, Jubin=false, Jon=true}

        ConcurrentHashMap.newKeySet 使用 KeySetView 创建新的 HashMap

        ConcurrentHashMap.KeySetView<String, Boolean> keySetView = ConcurrentHashMap.newKeySet();
        keySetView.add("Feba");
        System.out.println("keySetView = " + keySetView);
        System.out.println("keySetView.getMap() = " + keySetView.getMap());
        

        keySetView = [Feba] keySetView.getMap() = {Feba=true}

        keySetView.getMap().put("BeN",Boolean.TRUE);
        System.out.println("keySetView = " + keySetView);
        System.out.println("keySetView.getMap() = " + keySetView.getMap());
        

        keySetView = [BeN, Feba] keySetView.getMap() = {BeN=true, Feba=true}

        【讨论】:

          【解决方案5】:

          你错了。 newSetFromMap() 不提供线程安全。再次检查 Javadoc。

          还有一个小问题就是这两种方法的输入类型不同。

          【讨论】:

          • 呃,我的错。首先:我的意思是写Collections.newSetFromMap(»ConcurrentHashMap«) - 所以,手头的问题:从newSetFromMap(...) 获得的集合,使用来自java.util.concurrent 的映射,仍然是线程安全的吗?
          • @fbahr 正如我所说,检查 Javadoc。它包含答案。
          • ... 并且 Javadoc 说“结果集显示与支持映射相同的顺序、并发性和性能特征”,因此如果将它与并发映射一起使用,则该集合也是并发的设置。
          • 很遗憾,那些投票的人回答错误。大卫的问题是正确的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-20
          • 2011-01-20
          • 2011-07-02
          • 1970-01-01
          • 2010-11-25
          • 2010-11-20
          相关资源
          最近更新 更多