2

我有一个需要澄清的并发程序。第一个程序被认为是原子的,而第二个不是。

注意:这里的//注释并不意味着它 - 它们的意思是它是另一个与另一个同时执行的进程。

这是第一个:

int x = 0, y = 0;

co
   x = y + 1;      // y = y + 1;
oc

上面的程序可以被认为是原子的——但我不明白为什么会这样。但是下一个程序不是。

int x = 0, y = 0;

co
   x = y + 1;      // y = x + 1;
oc

我知道原子动作是一种编程指令,它可以不可分割地改变计算机系统的状态,也知道从寄存器加载和存储值是典型的原子动作。那么上面发生了什么?

4

3 回答 3

3

在您的第一种情况下,您总是会y在增量之前或之后遇到。由于操作是异步的,您无法分辨哪个,但它没有任何区别 - 唯一可观察到的效果是x在一种情况下大于 1 而不是另一种情况,这可能是基于两者的排序发生的陈述。

在第二种情况下,您可能会遇到 x 和 y 的结果值与语句的任一顺序不一致的情况,因为 x 和 y 在任一被修改之前都已获取。

第一种情况实际上并不是 Java 对“原子”的定义(并且与编译器可能生成的任何“原子”指令无关),而是简单的编程。

于 2012-05-18T11:10:49.010 回答
1

请注意以下事实:

示例 1. varx不是共享的,只是y共享的。左线程严格来说是y读,右线程是写y。由于单个读取或写入操作是原子的,因此不存在竞争条件。

示例 2. 两个 var 都是共享的;仅这一事实就会使操作成为非原子操作,但由于读取和写入的相互依赖性,这更加复杂。左线程:读后y跟写x,右线程:读后x跟写y。这些操作可以按任何顺序交错;甚至与程序顺序不兼容的顺序也是可能的。

在第一个示例中,任何执行最终都会得到可以解释为x = y + 1;之前执行y = y + 1;或反之亦然的结果。第二个结果可能与这些解释中的任何一个都不兼容——这就是为什么操作不是原子的。

于 2012-05-18T11:08:16.750 回答
0

就线程而言,大多数是原子的,这意味着在另一个线程可以访问之前,需要完全访问并执行一个语句块。就像这样

x= x+1 ;

现在当一个tread正在访问变量x来读写它的值时,如果其他线程也尝试读写它,那么由于不幸的时间(称为Race Condition)会导致问题,比如线程A读取变量x的值,这可能是0,当时线程 B 读取并将值写入 x 为 1,现在当线程 A 将值写入 x 时,x 也将为 1,因为线程 A 知道 x 是 0,但实际上它是 1。

int x = 0, y = 0;

co
   x = y + 1;      // y = y + 1;
oc

x 是原子的,y 值必须由同一个线程一次读取和写入,如果多个线程访问它,则会给出不一致的结果。

int x = 0, y = 0;

co
   x = y + 1;      // y = x + 1;
oc

另一方面,这不是原子的,因为 x=y+1 不会影响 y=x+1 根据对 x 的 fetch 和 y 在这里完成。

于 2012-05-18T11:15:33.953 回答