当前位置: 首页 > 面试题库 >

如何使ConcurrentHashMap线程中的更新BigDecimal安全

李奕
2023-03-14
问题内容

我正在制作一个需要一堆日记条目并计算总和的应用程序。

下面的方法是在有 多个线程 调用该addToSum()方法时是线程/并发安全的。我想确保每个电话都能正确更新总数。

如果不安全,请说明为确保线程安全我该怎么做。

我需要synchronize获取/放置还是有更好的方法?

private ConcurrentHashMap<String, BigDecimal> sumByAccount;

public void addToSum(String account, BigDecimal amount){
    BigDecimal newSum = sumByAccount.get(account).add(amount);
    sumByAccount.put(account, newSum);
}

非常感谢!

更新:

谢谢大家的回答,我已经知道上面的代码 不是线程安全的

感谢Vint建议AtomicReference使用替代synchronize。我以前AtomicInteger用来保存整数和,我想知道BigDecimal是否有类似的东西。

关于两者的利弊是否有定论?


问题答案:

您可以像其他建议的那样使用同步,但是如果需要最小限度的解决方案,则可以尝试AtomicReference作为BigDecimal的存储

ConcurrentHashMap<String,AtomicReference<BigDecimal>> map;

public void addToSum(String account, BigDecimal amount) {
    AtomicReference<BigDecimal> newSum = map.get(account);
    for (;;) {
       BigDecimal oldVal = newSum.get();
       if (newSum.compareAndSet(oldVal, oldVal.add(amount)))
            return;
    }
}

编辑-我将进一步解释:

AtomicReference使用CAS原子地分配单个引用。循环说明了这一点。

如果存储在AtomicReference中的当前字段== oldVal
[它们在内存中的位置,而不是它们的值],则用替换存储在AtomicReference中的字段的值oldVal.add(amount)。现在,在for循环之后的任何时候,调用newSum.get()都会有一个BigDecimal对象被添加到其中。

您想在此处使用循环,因为可能有两个线程试图将它们添加到同一AtomicReference中。可能发生一个线程成功而另一个线程失败的情况,如果发生这种情况,请尝试使用新增加的值。

如果线程争用程度适中,这将是更快的实现,而如果争用程度较高,则最好使用 synchronized



 类似资料:
  • HashMap的底层算法采用了链地址法来解决哈希冲突 哈希表 在数据结构中有一种称为哈希表的数据结构,它实际上是数组的推广。如果有一个数组,要最有效的查找某个元素的位置,如果存储空间足够大,那么可以对每个元素和内存中的某个地址对应起来,然后把每个元素的地址用一个数组(这个数组也称为哈希表)存储起来,然后通过数组下标就可以直接找到某个元素了。这种方法术语叫做直接寻址法。这种方法的关键是要把每个元素和

  • 问题内容: 在javadoc中,ConcurrentHashMap如下: 检索操作(包括get)通常不会阻塞,因此可能与更新操作(包括put和remove)重叠。检索反映了自启动以来最新完成的更新操作的结果。对于诸如putAll和clear的聚合操作,并发检索可能仅反映某些条目的插入或删除。同样,迭代器和枚举返回的元素反映了在创建迭代器/枚举时或此后某个时刻哈希表的状态。他们不抛出Concurre

  • 我只是想探讨一下ThreadSafe是什么意思? 以下是我的理解: 对我来说,它看起来像;允许多个线程同时访问一个集合;这与它的同步无关。例如,任何没有同步关键字的方法;是线程安全的,意味着多个线程可以访问它。 由开发人员选择在此方法上维护更多逻辑(同步),以便在多线程访问数据时保持数据完整性。这与线程安全是分开的。 如果我的上述陈述是错误的;只需阅读下面的 JAVA DOC for 'Concu

  • 我正在从服务器接收UDP数据,我想将UDP数据显示给。但每次都会发生NullPointerException。我不知道为什么。 下面是我的代码: 这个类是线程,用于继续接收UDP数据 我应该做什么来向TextView显示'str'? 这是StackTrace: java.lang.NullPoInterException:尝试在Android.Content.ContextWrapper.GetA

  • 问题内容: 我刚刚开始进行android开发,并且更新UI确实使我很烦:/ 到目前为止,这是我一直在努力的工作- 它工作正常,但是每个人都说要在主线程中做图形,所以我正在尝试(但失败)将其传递给另一个线程。麻烦的是,我真的不知道怎么做,因为我从未真正使用过线程。 Google给出的有关使用Threads的示例似乎并不十分清楚,我也无法真正按照自己的意愿去做。我可以请某人在这里给我一个最基本的例子,

  • 问题内容: 据我所知,这是可变的,因此,如果多个线程试图访问和修改它,则不是线程安全的。我们如何使用客户端锁定或组合(包装器)使其成为线程安全的? 问题答案: 按照从好到坏的顺序: 根本不使用它,请查看Java 8的新Date and Time API。 完全不使用它,请查看jodatime 在所有的,使用不使用或一成不变的原始与代表 纪元时间 封装它。始终返回的防御性副本,从不引用内部对象 在实