2
这不是关于LongAdder如何工作的问题,而是关于一个有趣的实现细节,我无法弄清楚。LongAdder Striped64 wasUncontended实现细节
下面是从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次进入longAccumulate方法(n> 1)并且繁忙的旋转处于第一个循环时。
就像这段代码所说的:如果你(某个线程)之前已经在这里,并且你在特定Cell插槽上有一些争用,请不要试图将CAS值赋给已经存在的值,而是重新刷新探测。
我真的希望我会对某人有所帮助。
1)我知道这是从哪里来的,但thx添加它的方式。 2)该死!我认为* CAS已知失败*意味着下一个CAS操作将失败,而不是前一个。我很喜欢你的猜测,他们可能有测试证明这是对代码的最佳补充。非常感谢您的意见。 – Eugene
是的,我现在对你的理论有99%的把握(再次查看代码后)。对我而言,这是违反直觉的,但是对于维护该代码的人来说,这可能会使事例变得有意义。再一次,谢谢你,我会接受这一点。 – Eugene
是的,这是最明智的解释。尝试使用CAS在某个时间递增整数的紧凑竞争循环。在激烈的争论中,你可以很容易地拥有90 +%不成功的CAS。 – Voo