我在多线程应用程序中常用的数据结构是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
?
答案 0 :(得分:5)
我强烈建议您使用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()
指定并发级别。您可能会觉得有用:
指导更新操作中允许的并发性。用作内部尺寸的提示。该表在内部进行分区,以尝试允许指定数量的并发更新而不会发生争用。因为对这些分区的条目分配不一定是统一的,所以观察到的实际并发性可能会有所不同。
答案 1 :(得分:0)