【问题标题】:Pattern for Java ConcurrentHashMap of Sets集合的 Java ConcurrentHashMap 模式
【发布时间】:2012-03-22 12:29:10
【问题描述】:

我在多线程应用程序中常用的数据结构是 ConcurrentHashMap,我想在其中保存一组共享相同键的项目。为特定键值安装第一项时会出现问题。

我一直使用的模式是:

final ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new ConcurrentHashMap<KEYTYPE, Set<VALUETYPE>>();
// ...
Set<VALUETYPE> newSet = new HashSet<VALUETYPE>();
final Set<VALUETYPE> set = hashMap.putIfAbsent(key, newSet)
if (set != null) {
  newSet = set;
}
synchronized (newSet) {
  if (!newSet.contains(value)) {
    newSet.add(value);
  }
}

是否有更好的模式来执行此操作?这甚至是线程安全的吗?内部Set 有比java.util.HashSet 更好的类吗?

【问题讨论】:

    标签: java concurrent-programming concurrenthashmap


    【解决方案1】:

    我强烈建议为此使用Google Guava 库,特别是Multimap 的实现。 HashMultimap 是您最好的选择,但如果您需要并发更新选项,则需要使用 Multimaps.synchronizedSetMultimap() 将其包装在委托中。

    另一种选择是使用ComputingMap(也来自Guava),这是一个映射,如果从调用get(Key) 中返回的值不存在,它会在此处被实例化。 ComputingMaps 是使用 MapMaker 创建的。

    您问题中的代码大致如下:

    ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new MapMaker()
                     .makeComputingMap(
            new Function<KEYTYPE, VALUETYPE>() {
             public Graph apply(KEYTYPE key) {
               return new HashSet<VALUETYPE>();
             }
           });
    

    Function 只会在调用 get() 以获取特定键时才会被调用,否则会返回 null。这意味着您可以这样做:

    hashMap.get(key).put(value);
    

    如果HashSet&lt;VALUETYPE&gt; 尚不存在,则可以放心地创建它。

    MapMaker 也很重要,因为它可以让您控制返回的 Map 的调整,例如,让您可以使用方法 concurrencyLevel() 指定并发级别。您可能会发现这很有用:

    指导更新操作之间允许的并发。用作内部尺寸调整的提示。该表在内部进行了分区,以尝试允许指定数量的并发更新而不会发生争用。由于对这些分区的条目分配不一定是统一的,因此观察到的实际并发可能会有所不同。

    【讨论】:

    • Guava 集合提供了什么样的线程安全保证?来自HashMultimap 的 JavaDocs:“当任何并发操作更新多映射时,此类不是线程安全的。并发读取操作将正常工作。要允许并发更新操作,请通过调用 Multimaps.synchronizedSetMultimap(com.google. common.collect.SetMultimap)。”在java.util.* 集合中,添加了concurrent 包,因为Collections.synchronizedMap() 的性能很差。
    • 这可能是您需要评估自己的事情。另一种选择是使用计算地图——我也会用一个例子来更新我的答案。
    • Guava 不提供完全并发的Multimap,主要是因为它非常很难做到。
    • 也就是说,我认为你正在按照我的方式做。
    • @LouisWasserman 当你说“你是”时,你指的是 OP 还是我? :)
    【解决方案2】:

    我认为使用java.util.concurrent.ConcurrentSkipListMapjava.util.concurrent.ConcurrentSkipListSet 可以帮助您解决并发问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      • 2014-12-29
      • 1970-01-01
      • 2014-01-10
      • 2020-08-22
      • 2014-03-20
      • 1970-01-01
      相关资源
      最近更新 更多