"atomic"编程中是什么意思?



在《高效Java》一书中,它指出:

语言规范保证阅读或书写变量是原子的,除非该变量是类型CCD_ 1或CCD_,17.4.7].

在Java编程或一般编程的上下文中,"原子"是什么意思?

这里有一个例子:假设foolong类型的变量,那么以下操作不是原子操作(在Java中(:

foo = 65465498L;

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

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

一个简单的方法是使变量不稳定:

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;

"原子操作"是指从所有其他线程的角度来看似乎是即时的操作。当担保适用时,您不需要担心部分完整的操作。

它"在系统的其他部分看来是瞬间发生的",在计算过程中属于线性化的范畴。进一步引用链接文章:

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

因此,例如,在数据库系统的上下文中,可以有"原子提交",这意味着你可以将更新的变更集推送到关系数据库,这些变更要么全部提交,要么在发生故障时根本不提交,这样数据就不会损坏,并且由于锁和/或队列,下一个操作将是不同的写入或读取,但仅在事实之后。在变量和线程的上下文中,这与应用于内存的情况基本相同。

你的话强调了这需要而不是在所有情况下都是预期行为。

刚刚发现后原子与非原子操作对我很有帮助。

"如果一个作用于共享内存的操作相对于其他线程在一个步骤中完成,那么它就是原子操作

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

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

如果您有几个线程执行下面代码中的方法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; }
}

调用long0的线程可以读取0、1234567890L或某个其他随机值,因为语句i = 1234567890L不能保证对于long是原子的(JVM可以在两个操作中写入前32位和后32位,线程可能会观察到介于两者之间的i(。

在Java中,除long和double之外的所有类型的读写字段都以原子方式发生,如果该字段是用volatile修饰符声明的,则即使是long和double也以原子方式读写。也就是说,我们100%地得到了那里发生的事情,也不可能在变量中有任何中间结果。

简单地说,原子意味着操作要么完成,要么不完成。其他线程或CPU不会在操作过程中捕捉到它。

相关内容

  • 没有找到相关文章

最新更新