当前位置: 首页 > 知识库问答 >
问题:

在并发HashMap中,如何同步更新?

董凡
2023-03-14

假设,我有如下 concurrentHashMap 代码:

ConcurrentHashMap<Integer,Integer> balances = new ConcurrentHashMap<>();

public void add(int accountId, int amountToAdd){
     int currentBalance = balances.get(accountId);
     balances.put(accountId, currentBalance + amountToAdd);
}

add 方法是从多个线程调用的,可以尝试同时更新同一 accountId 的数量。

如何确保currentBalance在< code>get和< code>put之间不发生变化?因为根据我的理解,如果线程在执行< code>get后抢占,同时其他线程更新余额,< code>put将使用旧余额执行更新。

共有2个答案

卜方伟
2023-03-14

您可以使用 AtomicIntegers 的哈希图:

ConcurrentHashMap<Integer,AtomicInteger> balances = new ConcurrentHashMap<>();

原子整数实现比较和交换操作。

然后:

public void add(int accountId, int amountToAdd){
     balances.get(accountId).addAndGet( amountToAdd );
}

要创建一个新的帐户,并且不要覆盖已经创建的帐户,并且由另一个线程初始化一些金额,使用这个:

public void addNewAccount(int accountId){
     balances.putIfAbsent( accountId, new AtomicInteger(0) );
}

您还可以组合使用两个 Metod 并仅使用一个:

public void add(int accountId, int amountToAdd){
     balances.putIfAbsent( accountId, new AtomicInteger(0) );
     balances.get(accountId).addAndGet( amountToAdd );
}
钱哲茂
2023-03-14

Java8向Map接口添加了一系列更新方法,并为ConcurrentHashMap提供了原子性保证。在你的情况下,你可以这样做:

public void add(int accountId, int amountToAdd){
    balances.computeIfPresent(accountId, (key, currentBalance) -> currentBalance + amountToAdd);
}

整个方法调用以原子方式执行。在计算过程中,其他线程在此映射上尝试的某些更新操作可能会被阻止,因此计算应简短,并且不得尝试更新此映射的任何其他映射。

 类似资料:
  • 当使用并发hashmap时,我是否需要将put环绕在一个同步块上,是否存在竞争条件:

  • 同步(Synchronization) 线程间的通信主要是通过共享访问字段以及其字段所引用的对象来实现的。这种形式的通信是非常有效的,但可能导致2种可能的错误:线程干扰(thread interference)和内存一致性错误(memory consistency errors)。同步就是要需要避免这些错误的工具。 但是,同步可以引入线程竞争(thread contention),当两个或多个线程

  • 我有一个并发HashMap,我在其中执行以下操作: 我的问题是——是否没有必要做额外的 检查synschronized块内部,以便其他线程不会初始化相同的hashmap值? 也许检查是必要的,但我做错了?我在做的事情似乎有点愚蠢,但我认为这是必要的。

  • 主要内容:实例下面是一个具有同步功能的多线程示例,这是和上篇文章同样的例子,它依次打印计数器值,每次运行它时,它产生相同的结果。 实例 每次运行此程序时都会产生相同的结果 -

  • 问题内容: 我有一个Web应用程序,人们需要资源。使用同步哈希映射来缓存此资源以提高效率。这里的问题是,当两个不同的请求同时到达同一未缓存资源时:检索资源的操作占用大量内存,因此我想避免为同一资源多次调用它。 有人可以告诉我以下代码段是否存在任何潜在问题吗?提前致谢。 问题答案: 一个可能的问题是,您通过在一个块内执行来创建不必要的竞争,因此许多线程无法同时检索其(独立)资源。这可以通过使用map

  • 问题内容: 是用什么包装类之间的差异上,和? 它只是能够在迭代()的同时进行修改吗? 问题答案: 同步: 每种方法都使用对象级锁进行同步。因此,synchMap上的get和put方法获取一个锁。 锁定整个集合是性能开销。当一个线程保持该锁时,其他任何线程都不能使用该集合。 是在JDK 5中引入的。 在对象级别没有锁定,锁定的粒度要好得多。对于,锁定可以处于哈希图存储桶级别。 较低级别的锁定的结果是