这不是关于 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 将失败的确定性在哪里?至少这对我来说真的很令人困惑,因为这种检查只对一种情况有意义:当某个线程第 n 次(n > 1)进入longAccumulate方法并且忙自旋处于它的第一个周期时。
就像这段代码在说:如果您(某个线程)以前曾来过这里并且您对特定的 Cell 插槽有一些争用,请不要尝试将您的值 CAS 到已经存在的值,而是重新散列探测。
老实说,我希望我会对某人有意义。