简体   繁体   English

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

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

In the Effective Java book, it states:在有效的 Java 书中,它指出:

The language specification guarantees that reading or writing a variable is atomic unless the variable is of type long or double [JLS, 17.4.7].语言规范保证读取或写入变量是原子的,除非变量的类型为longdouble [JLS, 17.4.7]。

What does "atomic" mean in the context of Java programming, or programming in general?在 Java 编程或一般编程的上下文中,“原子”是什么意思?

Here's an example: Suppose foo is a variable of type long , then the following operation is not an atomic operation ( in Java ):这是一个例子:假设foo是一个long类型的变量,那么以下操作不是原子操作(在 Java 中):

foo = 65465498L;

Indeed, the variable is written using two separate operations: one that writes the first 32 bits, and a second one which writes the last 32 bits.实际上,变量是使用两个单独的操作写入的:一个是写入前 32 位,第二个是写入后 32 位。 That means that another thread might read the value of foo , and see the intermediate state.这意味着另一个线程可能会读取foo的值,并查看中间状态。

Making the operation atomic consists in using synchronization mechanisms in order to make sure that the operation is seen, from any other thread, as a single, atomic (ie not splittable in parts), operation.使操作原子化包括使用同步机制以确保操作从任何其他线程被视为单个原子(即不可拆分成部分)操作。 That means that any other thread, once the operation is made atomic, will either see the value of foo before the assignment, or after the assignment.这意味着任何其他线程,一旦操作成为原子,要么在赋值之前,要么在赋值之后看到foo的值。 But never the intermediate value.但绝不是中间值。

A simple way of doing this is to make the variable volatile :一个简单的方法是使变量 volatile

private volatile long foo;

Or to synchronize every access to the variable:或者同步对变量的每次访问:

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

Or to replace it with an AtomicLong :或者用AtomicLong替换它:

private AtomicLong foo;

"Atomic operation" means an operation that appears to be instantaneous from the perspective of all other threads. “原子操作”是指从所有其他线程的角度来看似乎是瞬时的操作。 You don't need to worry about a partly complete operation when the guarantee applies.当保证适用时,您无需担心部分完成的操作。

It's something that "appears to the rest of the system to occur instantaneously", and falls under categorisation of Linearizability in computing processes.它是“在系统的其余部分看来是立即发生的”,并且属于计算过程中的线性化分类。 To quote that linked article further:进一步引用该链接文章:

Atomicity is a guarantee of isolation from concurrent processes.原子性是与并发进程隔离的保证。 Additionally, atomic operations commonly have a succeed-or-fail definition — they either successfully change the state of the system, or have no apparent effect.此外,原子操作通常有一个成功或失败的定义——它们要么成功地改变系统的状态,要么没有明显的影响。

So, for instance, in the context of a database system, one can have 'atomic commits', meaning that you can push a changeset of updates to a relational database and those changes will either all be submitted, or none of them at all in the event of failure, in this way data does not become corrupt, and consequential of locks and/or queues, the next operation will be a different write or a read, but only after the fact.因此,例如,在数据库系统的上下文中,可以有“原子提交”,这意味着您可以将更新的变更集推送到关系数据库,这些变更要么全部提交,要么根本不提交发生故障时,这样数据不会损坏,并且锁和/或队列的后果,下一个操作将是不同的写入或读取,但仅事后。 In the context of variables and threading this is much the same, applied to memory.在变量和线程的上下文中,这与应用于内存的情况大致相同。

Your quote highlights that this need not be expected behaviour in all instances.你的报价亮点:这并不需要指望在所有情况下的行为。

Just found a post Atomic vs. Non-Atomic Operations to be very helpful to me.刚刚发现一篇Atomic vs. Non-Atomic Operations对我很有帮助。

"An operation acting on shared memory is atomic if it completes in a single step relative to other threads. “如果一个操作相对于其他线程在单个步骤中完成,那么作用于共享内存的操作就是原子的。

When an atomic store is performed on a shared memory, no other thread can observe the modification half-complete.当在共享内存上执行原子存储时,没有其他线程可以观察到修改半完成。

When an atomic load is performed on a shared variable, it reads the entire value as it appeared at a single moment in time."当对共享变量执行原子加载时,它会读取单个时刻出现的整个值。”

If you have several threads executing the methods m1 and m2 in the code below:如果您有多个线程执行以下代码中的 m1 和 m2 方法:

class SomeClass {
    private int i = 0;

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

you have the guarantee that any thread calling m2 will either read 0 or 5.您可以保证任何调用m2线程都将读取 0 或 5。

On the other hand, with this code (where i is a long):另一方面,使用此代码(其中i很长):

class SomeClass {
    private long i = 0;

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

a thread calling m2 could read 0, 1234567890L, or some other random value because the statement i = 1234567890L is not guaranteed to be atomic for a long (a JVM could write the first 32 bits and the last 32 bits in two operations and a thread might observe i in between).调用m2的线程可以读取 0、1234567890L 或其他一些随机值,因为语句i = 1234567890L不能保证long是原子的(JVM 可以在两个操作和一个线程中写入前 32 位和后 32 位)可能会观察到i介于两者之间)。

In Java reading and writing fields of all types except long and double occurs atomically, and if the field is declared with the volatile modifier, even long and double are atomically read and written.在Java中,除long和double之外的所有类型的字段读写都是原子发生的,如果字段是用volatile修饰符声明的,那么long和double也是原子读写的。 That is, we get 100% either what was there, or what happened there, nor can there be any intermediate result in the variables.也就是说,我们 100% 得到了那里发生了什么,或者那里发生了什么,变量中也不可能有任何中间结果。

In simple words, the atomic means the operation will be either completed or not.简单来说,原子意味着操作要么完成,要么不完成。 The other threads or CPUs won't catch it in the middle of the operation.其他线程或 CPU 不会在操作中间捕获它。

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

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