ConcurrentHashMap内のAtomicIntegerに追加する - java、マルチスレッド、並行処理、java.util.concurrent、concurrenthashmap

私は以下を定義した

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

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

テストの後、私が得ている値は予想通り、ここに競争条件があると思う。誰かが、この関数がreplace関数でgetコールをラップすることによってスレッドセーフであると考えられるかどうかを知っていますか?

回答:

回答№1は2

あなたのコードにはいくつか問題があります。最大の問題は、あなたが「戻り値」を無視していることです。 ConcurrentHashMap.replace:交換が行われなかった場合(別のスレッドが並行して交換を行ったため)、そのまま進む かのように それは起こった。これがあなたが間違った結果を出す主な理由です。

私はまた、 " AtomicInteger すぐに別のものに交換してください AtomicInteger;たとえあなたがこの仕事を得ることができたとしても、単純に理由はありません。

最後に、私はあなたが staffValues.get(100) 二度。私は現在のコードにバグを引き起こすとは思っていません - あなたの正確さは、最初の呼び出しよりも "新しい"結果を返す2番目の呼び出しにのみ依存します。 実際に保証される ConcurrentHashMap - それは壊れやすく、微妙で混乱します。一般的に、 ConcurrentHashMap.replace3番目の引数は、2番目の引数を使って計算したものでなければなりません。

全体的には、コードを単純化するには、 AtomicInteger

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

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

または使用しないことによって replace (そしておそらくは ConcurrentMapあなたがこの地図に触れているかどうかに応じて):

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

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

回答№2の場合は1

このような状況を処理するには、 computeIfAbsent メソッド( compute @ the8472が推奨する方法)

computeIfAbsent 2つの引数、キー、および Function<K, V> 既存の値がない場合にのみ呼び出されます。 AtomicIntegerは複数のスレッドからインクリメントするスレッドセーフなので、次の方法でeasely使用できます。

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

回答№3の場合は0

あなたは使用する必要はありません replace()。 AtomicIntegerは、増分したいときはいつでも置換する必要のない可変値です。実際には addAndGet 既にそれを所定の位置に増分する。

代わりに compute 存在しない場合はデフォルト値(おそらく0)をマップに置き、そうでなければ既存の値を取得してそれをインクリメントします。

一方、不変の値を使用したい場合はput Integer インスタンスの代わりにインスタンス AtomicInteger アトミック計算/置換/マージ操作でそれらを更新します。


関連する質問
メニュー
最も人気のある