Java 什么是;原子的;在编程中是什么意思?

Java 什么是;原子的;在编程中是什么意思?,java,atomic,Java,Atomic,在《有效Java》一书中,它指出: 语言规范保证读或写 变量为原子变量,除非变量类型为long或double[JLS, 17.4.7] 在Java编程或一般编程的上下文中,“原子”是什么意思?它是“在系统的其余部分看来是瞬间发生的”,属于计算过程中的分类。进一步引用该链接文章: 原子性是与并发进程隔离的保证。 此外,原子操作通常具有成功或失败的风险 定义-它们要么成功更改系统状态, 或者没有明显的效果 因此,例如,在数据库系统的上下文中,可以有“原子提交”,这意味着您可以将更新的变更集推送到关系

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

语言规范保证读或写 变量为原子变量,除非变量类型为
long
double
[JLS, 17.4.7]

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

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

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

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


您的引文强调,并非所有情况下都会出现这种行为。

这里有一个例子,因为一个例子往往比一个冗长的解释更清楚。假设
foo
long
类型的变量。以下操作不是原子操作:

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

使操作原子化包括使用同步机制,以确保从任何其他线程将操作视为单个原子(即,不可拆分为部分)操作。这意味着任何其他线程,一旦操作成为原子操作,就会在赋值之前或赋值之后看到
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
或将其替换为:


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

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}
您可以保证任何调用
m2
的线程都将读取0或5

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

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

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

刚刚发现一篇文章对我很有帮助

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

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

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


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

t一次。一次只能对变量执行一个操作。我怀疑哲学问题在于,注意到某些变量在默认情况下没有原子读写,将它们声明为
volatile long
volatile double
使读原子和写原子。为什么您认为“long”会在int”“不是吗?请看这里@entropy long和double赋值在Java中不保证是原子的。因此,您可以读取一个长文件,其中只有一半的位在赋值后被更新。因此,假设它在32位系统中运行。如果是64位系统呢?威尔·福=65465498L;那么是原子的吗?@Harke如果你运行的是64位Java,是的。这也适用于C#和.NET吗?如果是,为了让foo获得原子行为,CLR必须是64位?@Fabiano它确实适用,下面介绍如何在.NET中实现它,因为我们没有像Java那样的同步关键字。然后假设线程A分配长值,然后在中途线程B尝试读取它。如果操作A是原子的,那么线程B将等待它完成吗?这意味着原子操作将提供隐式线程安全?
private AtomicLong foo;
class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}
class SomeClass {
    private long i = 0;

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