我一直在使用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的任何操作负责线程安全。)

10-08 00:57