我在多线程应用程序中常用的数据结构是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
的类? 最佳答案
我强烈建议为此使用Google Guava库,特别是Multimap的实现。 HashMultimap是最好的选择,但是如果您需要并发更新请求,则需要使用Multimaps.synchronizedSetMultimap()将其包装在委托中。
另一个选择是使用ComputingMap
(也来自Guava),这是一个映射,如果从对get(Key)
的调用返回的值不存在,则在该位置进行实例化。 ComputingMap
是使用MapMaker创建的。
您问题中的代码大致为:
ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new MapMaker()
.makeComputingMap(
new Function<KEYTYPE, VALUETYPE>() {
public Graph apply(KEYTYPE key) {
return new HashSet<VALUETYPE>();
}
});
仅当调用特定键的
Function
否则返回null时,才会调用get()
。这意味着您可以执行以下操作:hashMap.get(key).put(value);
安全地知道
HashSet<VALUETYPE>
(如果尚不存在)已创建。MapMaker
也很重要,因为它具有控制权,可以调节返回的Map,例如,使用concurrencyLevel()
方法指定并发级别。您可能会发现有用:指导更新操作之间允许的并发。用作内部调整的提示。该表在内部进行了分区,以尝试允许指定数量的并发更新而没有争用。由于对这些分区的条目分配不一定是统一的,因此观察到的实际并发性可能会有所不同。