java - 在 ConcurrentHashMap 上进行的操作是线程安全的吗?

标签 java concurrency concurrenthashmap

private final ConcurrentHashMap<Float, VoteItem> datum = new ConcurrentHashMap<>();

public void vote(float graduation) {
    datum.putIfAbsent(graduation, new VoteItem(graduation, new AtomicInteger(0)));
    datum.get(graduation).getNum().incrementAndGet();
}

投票方法是完全线程安全的吗? VoteItem.getNum() 返回一个 AtomicInteger?或者是否有更好的方法来实现?

最佳答案

如果VoteItem#getNum()是线程安全的,例如。 G。返回最终属性,并且不会在并行线程中执行任何删除操作,您的代码也是线程安全的,因为 putIfAbsent() 没有机会覆盖现有条目,因此get() 没有机会返回被覆盖的条目。

但是有更常见的方法可以使用 putIfAbsent() 的结果来实现它,如果给定键存在,则返回现有值:

public void vote(float graduation) {
    VoteItem i = datum.putIfAbsent(graduation, new VoteItem(graduation, new AtomicInteger(1)));
    if (i != null)
        i.getNum().incrementAndGet();
}

这也处理并发删除的可能性。与您的代码相反,您的代码可以在 putIfAbsent()get() 之间执行并发删除,从而导致 NPE,但这里不会发生这种情况。

并考虑使用computeIfAbsent()而不是 putIfAbsent() 以避免不必要的 VoteItem 创建:

public void vote(float graduation) {
    datum.computeIfAbsent(graduation, g -> new VoteItem(g, new AtomicInteger(0)))
         .getNum()
         .incrementAndGet();
}

对结果调用 getNum() 是可能的,因为与 putIfAbsent() 相比,如果插入之前值不存在,则返回 null,它返回刚刚计算的结果值。

关于java - 在 ConcurrentHashMap 上进行的操作是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35909582/

相关文章:

java - 仅限 Spring Boot webapp localhost

java - HashMap使用方式的设计实现

java - java并发hashmap中clear的默认行为是什么

java - 在 Sonar 中排除生成的代码

java - 使用服务器 ip 而不是字母获取路径

java - 如果 JFrame 调整大小,则调整 JProgressBar 的大小

java - 为什么 HashTable 在 Java 中仍然存在,而 ConcurrentHashMap 比它更高效?

java - 您可以只使用 AtomicInteger 来创建 ReadWriteLock 锁吗?

java - JMM 中的执行和因果关系要求

java - 自动整数线程澄清