集合的Java ConcurrentHashMap的模式

Ral*_*lph 4 java concurrenthashmap concurrent-programming

我在多线程应用程序中常用的数据结构是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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这种操作有更好的模式吗?这是否是线程安全的?是否有更好的课程用于内心而Set不是java.util.HashSet

Ric*_*ich 5

我强烈建议您使用Google Guava库,特别是Multimap的实现.该HashMultimap将是你最好的选择,但如果你需要并发更新opterations你需要使用到它包装在一个委托Multimaps.synchronizedSetMultimap() .

另一个选择是使用ComputingMap(也来自Guava),这是一个映射,如果从调用返回的Value 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>();
         }
       });
Run Code Online (Sandbox Code Playgroud)

Function时的调用将只能被称为get()一个特定的密钥,否则返回null.这意味着您可以这样做:

hashMap.get(key).put(value);
Run Code Online (Sandbox Code Playgroud)

安全地知道HashSet<VALUETYPE>如果它已经存在则被创建.

MapMaker也是相关的,因为它为您提供了对返回Map的调优的控制,让您可以使用该方法指定例如并发级别concurrencyLevel().您可能会觉得有用:

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