我有这个地图定义:
TreeMap <String, Set<Integer>>
它可能包含数百万个条目,我还需要一个“自然顺序”(这就是为什么我选择了一个TreeMap,但如果需要我可以编写一个Comparator)。
所以,为了向地图添加元素我需要做的是:
我有这个实现工作正常:
private void addToMap (String key, Integer value){
Set<Integer> vs = dataMap.get(key);
if (vs == null){
vs = new TreeSet<Integer>();
dataMap.put(key,vs);
}
vs.add(value);
}
但我想避免搜索密钥然后放置元素(如果它不存在)(它将在巨大的地图上执行新的搜索)。
我想我可以使用ConcurrentHashMap.putIfAbsent
方法,但是:
阅读这篇文章:Java map.get(key) - automatically do put(key) and return if key doesn't exist?
有一个关于Guava MapMaker.makeComputingMap
的答案,但看起来这个方法已经不存在了。
在这种情况下,性能至关重要(一如既往:D),所以请告诉我你的建议。
提前致谢。
注意: 非常感谢您在短短几分钟内获得了许多帮助答案。 (我不知道选哪一个是最好的。)
我将对建议(TreeMultiMap,ConcurrentSkipListMap,TreeSet + HashMap)进行一些性能测试,并使用结果进行更新。我将选择性能最佳的那个,因为我想选择所有三个,但我不能。
注2
所以,我做了一些150万条目的性能测试,结果如下:
ConcurrentSkipListMap,它不能按预期工作,因为它用我提供的新空集替换现有值。我认为只有当密钥不存在时才设置值,所以我不能使用这个。 (我的错误)。
TreeSet + HashMap,工作正常,但没有提供最佳性能。它比单独的TreeMap或TreeMultiMap慢1.5倍。
TreeMultiMap提供了最佳性能,但它几乎与TreeMap相同。我将检查这一个作为答案。
再次感谢您的贡献和帮助。
答案 0 :(得分:2)
如果性能至关重要,我不会使用整数TreeSet,我会找到一个更轻量级的结构,如TIntArrayList或包含int
值的东西。我也会使用HashMap,因为它的查找是O(1)而不是O(log N)。如果您还需要对键进行排序,我会使用第二个集合。
我同意ConcurrentHashMap上的putIfAbsent是矫枉过正的,并且获取/放置在HashMap上可能是最快的选择。
ConcurrentSkipListMap可能是使用putIfAbsent的一个很好的选择,但我会确保它不会慢。
BTW甚至比执行get / put更糟糕的是创建一个你不需要的HashSet。
答案 1 :(得分:2)
PutIfAbsent具有并发的好处,即:如果许多线程同时调用它,则它们不必等待(它不在内部使用synchronized)。然而,这只是执行速度的一小部分,所以如果你只使用单线程,这将减慢速度。
如果您需要将其排序,请尝试ConcurrentSkipListMap。
答案 2 :(得分:2)
TreeMultiMap
可以是你需要的。