AtomicInteger.addAndGet(int)中使用无限循环的用法

3
在Java的java.util.concurrent.atomic包中,AtomicInteger类有一个addAndGet(int)方法,详情请参考此链接
public final int addAndGet(int delta) {
    for (;;) {
        int current = get();
        int next = current + delta;
        if (compareAndSet(current, next))
            return next;
    }
}

为什么在这里使用无限循环来设置一个值?
3个回答

5
这是一个CAS循环的典型示例。比较并设置是一种具有直接硬件支持的原子操作(通常有一些CPU指令在其背后)。它仅在当前值等于期望值时原子更新给定变量,并在一切顺利时返回true。通常,此循环仅执行一次。但是,在争用情况下(当其他线程尝试更新相同值时),可能会在通过get()读取当前值和通过compareAndSet更新它之间另一个线程成功更新它。在这种情况下,整个过程将重试,直到成功为止。
在这里使用无限循环只是一种风格问题。它可以使用普通的do-while循环来重新编写:
public final int addAndGet(int delta) {
    int current, next;
    do {
        current = get();
        next = current + delta;
    } while (!compareAndSet(current, next));
    return next;
}

2

compareAndSet或者简称CAS与非阻塞线程安全算法相关。在addAndGet中的增量操作是获取旧值,将其转换为新值,并使用CAS 尝试 设置新值,如果在增量期间未修改current。如果CAS失败,则会重试直到成功。这种策略在没有极端争用的情况下是高效的。


0
这里的动机是你最终将会“返回下一个”(eventually return next)。 这意味着条件为:
if (compareAndSet(current, next))

某个迭代会返回true。不知道确切的时间,所以需要循环直到它发生。如果您查看{{link1:compareAndSet}}的代码,您会发现它在成功时返回true,而您无法知道它在第一次尝试时是否成功:

如果成功则返回true。False表示实际值与期望值不相等。


看起来很简单,但它会阻塞执行,直到addAndGet返回。是否有一种替代的compareAndSet可以阻止执行,从而不需要for(;;)? - Developer Marius Žilėnas
@TagirValeev,我的错,我现在会更新解释。 - Vano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接