【问题标题】:Why is this statement considered Atomic?为什么这个语句被认为是原子的?
【发布时间】:2012-05-18 11:00:00
【问题描述】:

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

注意:// 在这里并不表示 cmets - 它们的意思是它是另一个进程与另一个进程同时执行。

这是第一个:

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

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

【问题讨论】:

  • @Keyser:阅读所有内容 - 这些不是 cmets
  • 你真的应该强调你的最后一行
  • @MichaelBorgwardt 是的,我明白了。

标签: java concurrency atomic


【解决方案1】:

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

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

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

【讨论】:

  • 你可以称它们为原子的,因为它们总是作为一个整体执行,只是它们的顺序是未知的。
  • 是的,但它与 Java 的“原子”实现无关——它本质上是原子的。
  • Java 的“原子”实现是指...AtomicReference? volatile var?
  • 我忘记了各种咒语是什么——我把我的不同语言都弄糊涂了,但是整套同步、易失、并发/原子类等等。这些都涉及使用一些机器指令来告诉处理器以一种或另一种方式同步内存,而上述代码序列不需要,第一个不需要它。
  • 但是在 Java int 上存在原子操作的概念,这里适用。
【解决方案2】:

请注意以下事实:

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

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

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

【讨论】:

    【解决方案3】:

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

    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 在这里完成。

    【讨论】:

    • x = y + 1 如果它们都涉及相同的变量,如何不影响第二个过程?我已经确定第一个程序的 x 和 y 的可能值是:假设进程 A,然后是进程 B; x = 1,y = 1。B 在 A 之前; x = 2, y = 1。在非原子程序中,假设A在B之前执行; x = 1, y = 2。最后是 B 在 A 之前; x = 2,y = 1。
    猜你喜欢
    • 2016-06-07
    • 1970-01-01
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 2020-03-13
    • 2019-10-30
    • 2018-01-21
    • 1970-01-01
    相关资源
    最近更新 更多