我一直在使用Java的ConcurrentMap作为可从多个线程使用的 map 。 putIfAbsent是一种很棒的方法,比使用标准映射操作更容易读/写。我有一些看起来像这样的代码:
ConcurrentMap<String, Set<X>> map = new ConcurrentHashMap<String, Set<X>>();
// ...
map.putIfAbsent(name, new HashSet<X>());
map.get(name).add(Y);
在可读性方面,这很棒,但是每次都需要创建一个新的HashSet,即使它已经在 map 中了。我可以这样写:
if (!map.containsKey(name)) {
map.putIfAbsent(name, new HashSet<X>());
}
map.get(name).add(Y);
进行此更改后,它会失去一些可读性,但无需每次都创建HashSet。在这种情况下哪个更好?我倾向于第一个,因为它更具可读性。第二个将表现更好,并且可能更正确。也许有比这两种方法更好的方法。
以这种方式使用putIfAbsent的最佳实践是什么?
最佳答案
并发很难。如果您要为并发映射而不是直接锁定而烦恼,那么不妨这样做。确实,不要进行不必要的查找。
Set<X> set = map.get(name);
if (set == null) {
final Set<X> value = new HashSet<X>();
set = map.putIfAbsent(name, value);
if (set == null) {
set = value;
}
}
(通常的stackoverflow免责声明:超出我的头脑。未经测试。未经编译。等等。)
更新: 1.8在
computeIfAbsent
中添加了ConcurrentMap
默认方法(以及Map
,这很有趣,因为ConcurrentMap
的实现是错误的)。 (并且1.7添加了“钻石算子” <>
。)Set<X> set = map.computeIfAbsent(name, n -> new HashSet<>());
(请注意,您应对
HashSet
中包含的ConcurrentMap
的任何操作负责线程安全。)