简体   繁体   English

在ConcurrentHashMap中,如何同步更新?

[英]In ConcurrentHashMap, how to synchronize update?

Suppose, I have concurrentHashMap code such as below: 假设我有并发HashMap代码,如下所示:

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

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

This add method is called from multiple threads, there can be attempt to update the amount of the same accountId at same time. 从多个线程调用此add方法,可以尝试同时更新同一accountId的数量。

How to ensure the currentBalance doesn't change between the get and the put ? 如何确保currentBalance在getput之间不变? Because from my understanding, if thread preempts after doing get , and meanwhile some other thread updates the balance, put will perform update with stale balance. 因为从我的理解来看,如果线程在执行get之后抢占了,同时其他一些线程更新了平衡, put将使用过时的平衡来执行更新。

Java 8 adds a bunch of update methods to the Map interface, with atomicity guarantees for ConcurrentHashMap . Java 8向Map接口添加了一堆更新方法,并为ConcurrentHashMap提供了原子性保证。 In your case, you could do something like this: 在您的情况下,您可以执行以下操作:

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

Javadoc Java文档

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. 在进行计算时,可能会阻止其他线程在此映射上进行的某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。

You can use a hashmap of AtomicIntegers: 您可以使用AtomicIntegers的哈希图:

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

AtomicInteger implements the compare and swap operation. AtomicInteger实现比较和交换操作。


And then: 接着:

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

to create a new accont - and don't overwrite an account already created and initialised with some amount by the other thread - use this: 创建一个新的帐户-不要覆盖另一个线程已经创建并初始化了一定金额的帐户-请使用以下命令:

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

you can also combine both metods and use only one: 您还可以结合使用两种方法,并且仅使用一种方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM