4

我正在查看类中addAndGet方法的 Java(Java 6) 源代码AtomicInteger

对应的代码如下:

public final int addAndGet(int delta) {
    for (;;) {
        int current = get();
        int next = current + delta;
        if (compareAndSet(current, next))
            return next;
    }
}

compareAndSet 方法调用本地方法来执行分配。主要有两个问题:

  1. 无限循环有什么帮助?
  2. 在什么情况下,“if (compareAndSet(current, next))”条件可能返回 false ?在这种情况下,代码可能会陷入无限循环。如果保证 compareAndSet 总是返回一个“真”,那么我们可以不完全取消这个检查吗?

decrementAndGet, getAndDecrement,getAndAdd方法也有类似的疑问。

4

1 回答 1

10

无限循环有什么帮助?

这意味着:重试直到成功。如果没有循环,它可能不会第一次成功(见下文)。

在什么情况下,“if (compareAndSet(current, next))”条件可能返回 false ?

如果两个线程同时尝试修改该值,就会发生这种情况。其中一个会先到达那里。另一个会失败。

想象两个线程(A 和 B)试图从 5 增加到 6

A: int current = get();  // current = 5
B: int current = get();  // current = 5
B: int next = current + delta;  // next = 6
B: if (compareAndSet(current, next))  // OK
          return next;
A: int next = current + delta;  // next = 6 
A: if (compareAndSet(current, next))  
    // fails, because "current" is still 5
    // and that does not match the value which has been changed to 6 by B

请注意,这个类的重点是避免锁定。所以相反,你有这种“乐观的货币控制”:假设没有其他人同时处理数据,如果结果证明是错误的,则回滚并重试。

在这种情况下,代码可能会陷入无限循环

并不真地。对于对值做某事的每个其他线程,它只能失败一次。

在第二次迭代中来自上面的线程 A:

A: int current = get();  => current now 6
A: int next = current + delta;  => next = 7
A: if (compareAndSet(current, next))  => now OK

如果其他线程不断更新该值,您可能会导致一个线程永远等待,但仅此而已。为避免这种情况,您需要对“公平”进行一些定义(并发包中的一些其他工具支持)。

于 2013-07-17T05:47:34.527 回答