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在get
和put
之间不发生变化?因为根据我的理解,如果线程在执行 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 );
}
假设,我有如下的 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在get
和put
之间不发生变化?因为根据我的理解,如果线程在执行 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 );
}