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

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

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


当前回答

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

其他回答

这是“对系统的其余部分来说,似乎是瞬间发生的”,并且属于计算过程中的线性化范畴。进一步引用这篇链接文章:

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

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.

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

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

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

刚刚发现一篇关于原子与非原子操作的文章对我很有帮助。

作用于共享内存的操作是原子的,如果它相对于其他线程在一个步骤中完成。 当在共享内存上执行原子存储时,没有其他线程可以观察到修改已完成一半。 当对共享变量执行原子加载时,它会读取该变量在某一时刻出现的整个值。”

这里有一个例子:假设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;