假设我有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的数量。
如何确保get
和put
之间的currentBalance不会发生变化?因为根据我的理解,如果线程在执行get
之后抢占,同时其他一些线程更新余额,put
将执行更新并保持陈旧平衡。
答案 0 :(得分:2)
Java 8为Map
接口添加了一堆更新方法,并为ConcurrentHashMap
提供了原子性保证。在你的情况下,你可以做这样的事情:
public void add(int accountId, int amountToAdd){
balances.computeIfPresent(accountId, (key, currentBalance) -> currentBalance + amountToAdd);
}
整个方法调用 以原子方式执行 。一些尝试 其他线程在此映射上的更新操作可能会被阻止 计算正在进行中,因此计算应该很短 简单,不得尝试更新此地图的任何其他映射。
答案 1 :(得分:1)
您可以使用AtomicIntegers的散列图:
ConcurrentHashMap<Integer,AtomicInteger> balances = new ConcurrentHashMap<>();
AtomicInteger实现compare and swap操作。
然后:
public void add(int accountId, int amountToAdd){
balances.get(accountId).addAndGet( amountToAdd );
}
创建一个新的accont - 并且不要覆盖已创建的帐户并通过其他线程初始化一些金额 - 使用此:
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 );
}