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

Posted

技术标签:

【中文标题】编程中的“原子”是啥意思?【英文标题】:What does "atomic" mean in programming?编程中的“原子”是什么意思? 【发布时间】:2013-02-09 20:04:06 【问题描述】:

在 Effective Java 一书中,它指出:

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

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

【问题讨论】:

一次一个操作。 一次只能对变量执行一个操作。 ibm.com/developerworks/library/j-jtp11234 我怀疑哲学问题属于codereview.stackexchange.com 注意到一些变量默认情况下没有原子读写,将它们声明为volatile longvolatile double使得读原子和写原子。 【参考方案1】:

这是“在系统的其余部分看来是瞬间发生的”,在计算过程中属于Linearizability 的分类。进一步引用链接的文章:

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

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

您的引述强调了这不是在所有情况下都是预期的行为。

【讨论】:

【参考方案2】:

举个例子:假设foolong类型的变量,那么下面的操作就不是原子操作(在Java中):

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;

【讨论】:

所以这是假设它在 32 位系统中运行。如果是 64 位系统呢?将 foo = 65465498L;那么是原子的? @Harke 如果你运行的是 64 位 Java,是的。 这是否也适用于 C# 和 .NET?如果是,为了让 foo 获得原子行为,CLR 必须是 64 位的? @F***o 它确实适用,这里是如何在 .NET 中实现它,因为我们没有像 Java 这样的同步关键字。 ***.com/questions/541194/… 然后让我们假设线程 A 分配 long 值,然后在中途线程 B 尝试读取它。如果操作A是原子的,那么线程B会等到它完成吗?这意味着原子操作将提供隐式线程安全?【参考方案3】:

如果您有多个线程执行下面代码中的方法 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 或其他一些随机值,因为对于 long 语句 i = 1234567890L 不能保证是原子的(JVM 可以写入前 32 位和后 32 位)两个操作中的位和一个线程可能会在两者之间观察到i)。

【讨论】:

为什么你认为“long”会导致问题,而“int”不会?请看这里geekswithblogs.net/BlackRabbitCoder/archive/2012/08/09/… @entropy long 和 double 赋值在 Java 中不保证是原子的。因此,您可以阅读很长的内容,其中只有一半的位在分配后被更新。【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

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

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

【讨论】:

【参考方案6】:

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

【讨论】:

以上是关于编程中的“原子”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

编程中的“存根”是啥意思?

Windows中的Shell编程 Shell指的是啥意思?

C语言编程中的字体颜色是啥意思

FLAG1在编程中是啥意思

编程中field是啥意思

fpga是啥意思?