繁体   English   中英

编程中的“原子”是什么意思?

[英]What does "atomic" mean in programming?

在有效的 Java 书中,它指出:

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

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

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

foo = 65465498L;

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

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

一个简单的方法是使变量 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;

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

它是“在系统的其余部分看来是立即发生的”,并且属于计算过程中的线性化分类。 进一步引用该链接文章:

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

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

你的报价亮点:这并不需要指望在所有情况下的行为。

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

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

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

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

如果您有多个线程执行以下代码中的 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介于两者之间)。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM