我有一个需要提供澄清的并发程序。第一个程序被认为是原子,而第二个程序不是。
注意: //
并不意味着这里的评论 - 它们意味着它是与另一个同时执行的另一个进程。
这是第一个:
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
我知道原子动作是一种编程指令,可以不可分割地改变计算机系统的状态,并且知道从寄存器加载和存储值是典型的原子动作。那么上面发生了什么?
答案 0 :(得分:3)
在第一种情况下,您将在增量之前或之后始终遇到y
。由于操作是异步的,你无法分辨哪个,但它没有任何区别 - 唯一可观察的效果是x
在一个案例中比另一个案件大1,这可能是基于订购这两个陈述。
在第二种情况下,您可能会遇到x和y的结果值与语句的任何顺序不一致的情况,因为x和y都是在修改之前获取的。
第一种情况不是Java的“原子”定义(并且与编译器可能生成的任何“原子”指令无关),而是简单的编程。
答案 1 :(得分:1)
请注意以下事实:
示例1.未共享Var x
,仅共享y
。左侧线程严格地是y
的读者,右侧线程是y
的作者。由于单个读或写操作是原子的,因此没有竞争条件。
示例2.两个vars是共享的;仅这一事实就会使操作成为非原子操作,但由于读写的相互依赖性,这更加复杂。左线程:读取y
之后写入x
,右线程:读取x
后写入y
。这些操作可以按任何顺序交错;甚至可以订购与程序顺序不兼容的订单。
在第一个例子中,任何执行结果都会以x = y + 1;
之前执行的y = y + 1;
或其他方式执行。第二个结果可能最终得出与这些解释中的任何一个都不相容的结果 - 这就是操作不是原子的原因。
答案 2 :(得分:0)
就线程而言,大多数原子意味着在另一个线程可以访问它之前需要访问并完成一个语句块。就像这样
x = x + 1;
现在当踏板正在访问变量x来读取和写入其值时,如果其他线程也尝试读取和写入它,那么由于不幸的计时(称为Race Condition)会导致问题,就像线程A读取变量x值一样这可能是0,并且在那时线程B读取并将值写入x为1,现在当线程A将值写入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上获取并且y在这里完成。