“原子”在编程中意味着什么?

时间:2013-02-24 16:57:38

标签: java atomic

在Effective Java一书中,它指出:

  

语言规范保证阅读或写作   变量是原子的,除非变量的类型为longdouble [JLS,   17.4.7]。

“原子”在Java编程或编程环境中意味着什么?

6 个答案:

答案 0 :(得分:327)

这是一个例子,因为一个例子通常比一个长的解释更清楚。假设foolong类型的变量。以下操作不是原子操作:

foo = 65465498L;

实际上,变量是使用两个独立的操作写入的:一个写入前32位,另一个写入最后32位。这意味着另一个线程可能会读取foo的值,并看到中间状态。

使操作原子化包括使用同步机制,以确保从任何其他线程看到操作为单个原子(即不可拆分的部分)操作。这意味着任何其他线程,一旦操作成为原子操作,将在赋值之前或赋值之后看到foo的值。但绝不是中间价值。

这样做的一个简单方法是制作variable volatile

private volatile long foo;

或者同步对变量的每次访问:

public synchronized void setFoo(long value) {
    this.foo = value;
}

public synchronized long getFoo() {
    return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized

或者用AtomicLong替换它:

private AtomicLong foo;

答案 1 :(得分:49)

“原子操作”是指从所有其他线程的角度看似乎是瞬时的操作。保证适用时,您无需担心部分完成的操作。

答案 2 :(得分:21)

这是“系统其他部分即时发生”的东西,并且在计算过程中属于Linearizability的分类。引用该链接文章:

  

原子性是与并发进程隔离的保证。   此外,原子操作通常具有成功或失败   定义 - 他们要么成功地改变了系统的状态,   或没有明显效果。

因此,例如,在数据库系统的上下文中,可以进行“原子提交”,这意味着您可以将更改的更改集推送到关系数据库,并且这些更改将全部提交,或者都不提交在发生故障的情况下,以这种方式数据不会损坏,并且锁定和/或队列的结果,下一个操作将是不同的写入或读取,但只有之后事实。在变量和线程的上下文中,这大致相同,适用于内存。

您的引言强调,在所有情况下,都是预期的行为。

答案 3 :(得分:11)

如果您有多个线程在下面的代码中执行方法m1和m2:

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

您可以保证任何调用m2的线程都将读取0或5。

另一方面,使用此代码(其中i为长):

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

调用m2的线程可以读取0,1234567890L或其他一些随机值,因为i = 1234567890L的语句long不能保证是原子的(JVM可以写第一个)两个操作中的32位和最后32位,并且线程可能会在其间观察到i

答案 4 :(得分:11)

刚发现帖子Atomic vs. Non-Atomic Operations对我很有帮助。

  

"如果相对于其他线程在一个步骤中完成,则对共享内存执行的操作是原子操作。

     

当在共享内存上执行原子存储时,没有其他线程可以观察到修改半完成。

     

当对共享变量执行原子加载时,它会读取单个时刻出现的整个值。"

答案 5 :(得分:0)

在Java中,除了long和double以外,所有类型的读取和写入字段都是原子发生的,并且如果使用volatile修饰符声明了该字段,则即使long和double也会被原子读取和写入。也就是说,我们得到的结果是100%,或者那里发生了什么,变量中也没有中间结果。