具有两个线程的良性数据竞争条件

时间:2012-11-29 12:37:48

标签: multithreading race-condition

这是竞争条件吗?

class A {
   int x; 

   update() {
      x = 5; 
   }

   retrieve() {
      y = x; 
   }
}

如果update()和retrieve()由两个不同的线程调用而没有任何锁定,假设共享变量的两次访问中至少有一次写入,则可以将其归类为竞争条件。但这在运行时是否真的成为问题?

1 个答案:

答案 0 :(得分:2)

没有锁,可能会发生三件事:

  1. y获取x(5)的新值。
  2. y获取x的旧值(很可能为0)。
  3. 如果写入int不是原子的,那么y可以获得任何其他值。
  4. 在Java中,对int的读取是原子的,因此第三种选择不可能发生。不保证其他语言的原子性。

    通过锁定,前两个选项也可以发生。

    但是,根据内存模型,还有一个额外的挑战。在Java中,如果写入未同步,则可以将其任意延迟,直到下一个同步点(synchronized块结束或访问volatile字段)。类似地,可以从先前的同步点(synchronized块的开始或对volatile字段的访问)任意缓存读取。这很容易导致过时缓存引起的问题。最终结果是,即使第一个选项应该发生,第二个选项也可能发生。

    在Java中,始终将volatile与可以从其他线程访问的字段一起使用,否则您将面临内存访问重新排序引起的难以调试的竞争条件。同样的警告适用于使用类似于Java的内存模型的其他语言 - 您可能需要告诉编译器不要进行这些优化。