ConcurrentHashMap中,如何同步更新?

In ConcurrentHashMap, how to synchronize update?

假设,我有如下的 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在getput之间不发生变化?因为根据我的理解,如果线程在执行 get 后抢占,同时其他线程更新余额,put 将使用陈旧的余额执行更新。

Java 8 向Map接口添加了一堆更新方法,ConcurrentHashMap具有原子性保证。在你的情况下,你可以这样做:

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

Javadoc

The entire method invocation is performed atomically. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.

您可以使用 AtomicIntegers 的哈希图:

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

AtomicInteger 实现了 compare and swap 操作。


然后:

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

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

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

您也可以结合使用两种方法,只使用一种方法:

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