Pridanie do aplikácie AtomicInteger v rámci ConcurrentHashMap - java, multithreading, súbežnosť, java.util.concurrent, concurrenthashmap

Mám nasledujúce definované

private ConcurrentMap<Integer, AtomicInteger>  = new ConcurrentHashMap<Integer, AtomicInteger>();

private void add() {
staffValues.replace(100, staffValues.get(100), new AtomicInteger(staffValues.get(100).addAndGet(200)));
}

After testing, the values I am getting are not očakáva sa, a myslím si, že tu existuje podmienka pretekov. Vie niekto, či by sa toto považovalo za zabezpečenie vlákien tým, že sa obalí volanie vo funkcii výmeny?

odpovede:

2 pre odpoveď č. 1

Existuje niekoľko problémov s vaším kódom. Najväčší je to, že ignorujete návratovú hodnotu ConcurrentHashMap.replace: ak nedôjde k výmene (v dôsledku iného vlákna, ktoré urobilo paralelu náhradu), jednoducho pokračujte ako keby stalo sa. To je hlavný dôvod, prečo ste sa dostali nesprávne výsledky.

Tiež si myslím, že je to chyba v návrhu, aby sa zmenil AtomicInteger a okamžite ho nahraďte iným AtomicInteger; aj keď môžete túto prácu dostať, jednoducho nie je dôvod na to.

Nakoniec si nemyslím, že by ste mali zavolať staffValues.get(100) dvakrát. Nemyslím si, že to spôsobí chybu v aktuálnom kóde - Vaša správnosť závisí len od druhého hovoru, ktorý vracia "novší" výsledok ako prvý, čo si myslím je skutočne zaručené ConcurrentHashMap - ale je to krehké a jemné a matné. Vo všeobecnosti, keď zavoláte ConcurrentHashMap.replace, jeho tretí argument by mal byť niečo, čo ste vypočítali pomocou druhého.

Celkovo môžete kód zjednodušiť, ak ho nepoužívate AtomicInteger:

private ConcurrentMap<Integer, Integer> staffValues = new ConcurrentHashMap<>();

private void add() {
final Integer prevValue = staffValues.get(100);
staffValues.replace(100, prevValue, prevValue + 200);
}

alebo nepoužívate replace (a možno ani nie ConcurrentMap, v závislosti od toho, ako sa inak dotknete tejto mapy:

private Map<Integer, AtomicInteger> staffValues = new HashMap<>();

private void add() {
staffValues.get(100).addAndGet(200);
}

1 pre odpoveď č. 2

Dobrý spôsob, ako zvládnuť takéto situácie, je používanie computeIfAbsent metóda (nie compute metóda, ktorú @ the8472 odporúča)

Na computeIfAbsent akceptuje 2 argumenty, kľúčom, a Function<K, V> ktorá bude volaná iba ak chýba existujúcu hodnotu.Pretože AtomicInteger je vlákno bezpečné narastal z viacnásobných vlákien, môžete ho easely nasledovným spôsobom:

staffValues.computeIfAbsent(100, k -> new AtomicInteger(0)).addAndGet(200);

0 pre odpoveď č. 3

Don "t musieť použiť replace(). AtomicInteger je premenlivé hodnoty, ktoré nie je potrebné nahradiť kedykoľvek chcete prírastok je.v skutočnosti addAndGet už inkrementuje ju na mieste.

Namiesto toho použite compute dať predvolenú hodnotu (pravdepodobne 0) do mapy keď žiadna nie je prítomný a inak už existujúce hodnoty a prírastku, ktorý.

Ak na druhej strane, ktorú chcete použiť nemenné hodnoty dal Integer inštancie namiesto AtomicInteger do mapy a aktualizovať ich s atómovú výpočtových/nahradiť/zlúčenie operácií.


Ponuka