【问题标题】:The getAndIncrement implementation of AtomicIntegerAtomicInteger 的 getAndIncrement 实现
【发布时间】:2013-11-14 22:02:36
【问题描述】:

AtomicInteger 的 getAndIncrement 实现执行以下操作:

public final int getAndIncrement() {
    for (;;) {
        int current = get(); // Step 1 , get returns the volatile variable
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    } }

不就是aVolatileVariable++的等价物吗? (我们知道这不是正确的用法)。如果没有同步,我们如何确保这个完整的操作是原子的?如果在步骤 1 中读取变量 'current' 后 volatile 变量的值发生了变化怎么办?

【问题讨论】:

    标签: java synchronization atomic volatile


    【解决方案1】:

    “秘诀”就在这个电话里:

    compareAndSet(current, next)
    

    如果原始 volatile 值在读取后同时更改,compareAndSet 操作将失败(并返回 false),从而强制代码继续循环。 p>

    【讨论】:

    • 一些 ISA(尤其是 x86)直接提供原子添加(或 fetch_add),例如 ``mov eax, 1` ; lock add [rdi], eax (memory+=eax, and register = old value from memory)。这不需要任何重试循环,因此它只需要等待获得对缓存行的独占访问权(就像任何存储一样)。一个好的 JVM 将具有此功能的特定于 x86 的实现。另见Can num++ be atomic for 'int num'?。但可以肯定的是,您可以从 CAS 重试循环中合成任意操作。
    • 当然,大多数非 x86 ISA 实际上具有 LL/SC (en.wikipedia.org/wiki/Load-link/store-conditional) 而不是 CAS(比较和交换)作为它们的原子原始构建块,所以再次一个好的 JVM 会实现稍微更有效率,并在 add 周围使用 LL/SC 重试循环,而不是使用根据 LL/SC 实现的实际 CAS,就像您实际使用此代码时可能会得到的那样。但这比完全在 x86 上避免重试循环没什么大不了的。
    猜你喜欢
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 2013-02-15
    • 2011-06-16
    相关资源
    最近更新 更多