これは、LongAdder がどのように機能するかという問題ではなく、私には理解できない興味深い実装の詳細に関する問題です。
Striped64 のコードは次のとおりです (いくつかの部分を切り取り、質問に関連する部分を残しました)。
final void longAccumulate(long x, LongBinaryOperator fn,
boolean wasUncontended) {
int h;
if ((h = getProbe()) == 0) {
ThreadLocalRandom.current(); // force initialization
h = getProbe();
wasUncontended = true;
}
boolean collide = false; // True if last slot nonempty
for (;;) {
Cell[] as; Cell a; int n; long v;
if ((as = cells) != null && (n = as.length) > 0) {
if ((a = as[(n - 1) & h]) == null) {
//logic to insert the Cell in the array
}
// CAS already known to fail
else if (!wasUncontended) {
wasUncontended = true; // Continue after rehash
}
else if (a.cas(v = a.value, ((fn == null) ? v + x : fn.applyAsLong(v, x)))){
break;
}
を除いて、コードからの多くのことは私には明らかです。
// CAS already known to fail
else if (!wasUncontended) {
wasUncontended = true; // Continue after rehash
}
次のCASが失敗するというこの確実性はどこにありますか? このチェックは単一のケースでのみ意味があるため、これは少なくとも私にとっては本当に混乱します。スレッドがlongAccumulateメソッドに n 回目 (n > 1) に入り、ビジー スピンが最初のサイクルにある場合です。
このコードは次のように言っているようです: あなた (一部のスレッド) が以前にここにいて、特定のセルスロットで競合が発生した場合は、値を既存のものに CAS しようとせず、代わりにプローブを再ハッシュしてください。
正直なところ、誰かにとって意味のあることを願っています。