这是竞争条件吗?
class A {
int x;
update() {
x = 5;
}
retrieve() {
y = x;
}
}
如果update()和retrieve()由两个不同的线程调用而没有任何锁定,假设共享变量的两次访问中至少有一次写入,则可以将其归类为竞争条件。但这在运行时是否真的成为问题?
答案 0 :(得分:2)
没有锁,可能会发生三件事:
y
获取x
(5)的新值。y
获取x
的旧值(很可能为0)。int
不是原子的,那么y
可以获得任何其他值。在Java中,对int
的读取是原子的,因此第三种选择不可能发生。不保证其他语言的原子性。
通过锁定,前两个选项也可以发生。
但是,根据内存模型,还有一个额外的挑战。在Java中,如果写入未同步,则可以将其任意延迟,直到下一个同步点(synchronized
块结束或访问volatile
字段)。类似地,可以从先前的同步点(synchronized
块的开始或对volatile
字段的访问)任意缓存读取。这很容易导致过时缓存引起的问题。最终结果是,即使第一个选项应该发生,第二个选项也可能发生。
在Java中,始终将volatile
与可以从其他线程访问的字段一起使用,否则您将面临内存访问重新排序引起的难以调试的竞争条件。同样的警告适用于使用类似于Java的内存模型的其他语言 - 您可能需要告诉编译器不要进行这些优化。