在ConcurrentHashMap中,如何同步更新?

时间:2016-05-18 19:52:57

标签: java multithreading concurrency concurrenthashmap

假设我有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的数量。

如何确保getput之间的currentBalance不会发生变化?因为根据我的理解,如果线程在执行get之后抢占,同时其他一些线程更新余额,put将执行更新并保持陈旧平衡。

2 个答案:

答案 0 :(得分:2)

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

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

Javadoc

  

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

答案 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 );
}