Java原子方法

时间:2013-10-21 10:26:28

标签: java atomic

我一直在研究Java API java.util.concurrent.atomic , 特别是 AtomicInteger 类。

方法评论说这些方法是原子的。

getAndIncrement()为例:

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

,正如文件记载的那样," 以原子方式将当前值增加一个。"

究竟是什么让这种方法成为原子? 从我所看到的,它完全是非原子的 - 在执行中涉及许多循环, 在执行声明期间

        int next = current + 1;

例如, next 的值可以由另一个线程设置。

4 个答案:

答案 0 :(得分:2)

原子性在compareAndSet(current, next)方法中处理。代码执行增量并仅在尚未更改时设置新值,并且以原子方式完成(或者伪造原子行为)。如果从那以后它被改变了,那就再试一次。所以它可能不是原子的,但它就像它一样。

答案 1 :(得分:1)

AtomicInteger使用volatile和amp;的组合。 CAS(比较和交换)用于整数计数器的线程安全实现。

阅读&写入volatile变量具有与使用同步代码块获取和释放监视器相同的内存语义。因此,JMM保证了易变场的可见性。

AtomicInteger类将其value字段存储在volatile变量中,因此它是传统volatile变量的装饰器,但它提供了唯一的非阻塞机制,用于在需要CAS的硬件级别支持(比较和设置)后更新值。在低到中等线程争用下,与同步阻塞增量操作相比,原子更新提供了更高的吞吐量。

这是AtomicInteger类的getAndIncrement()方法的实现。

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

}你可以看到没有获取锁来增加值,而是在无限循环中使用CAS来更新新值。

由于AtomicInteger不需要锁定,因此它可用于编写可扩展的应用程序,其中线程争用低至中等。

答案 2 :(得分:0)

如果你看一下没有循环和CAS会发生什么,那么这里的原子将是什么意思。

如果没有synchronized和compare and set(所以不需要循环),你的代码就像

public final int getAndIncrement() {

        int current = get();
        int next = current + 1;
        set(next);
        return current;

}

在多线程环境中,可能有两个线程将当前值视为0&尝试将值更新为一个。两个更新但值仅增加一个。显然没有同步,不能保证不会发生这种情况。

所以这就是compareAndSet的帮助,看看在递增到1之前值是否仍为零。因此,如果当前值为零,我们说只将compareAndSet设置为1,否则会失败。考虑到上面两个线程更新值的情况,最多只有一个线程将成功地将值增加到1而其他线程将失败。因此,尊重操作的原子性(“全有或全无”)。

答案 3 :(得分:0)

如果跟踪compareAndSet函数实现一直到汇编代码,你会发现它被翻译成单个汇编指令(cmpxchg for i486,sun jdk中的文件linux_i486.s),这是一条指令进行价值交换,从而提供所需的原子性而不是锁定。