如果只有一个写程序线程和一个读程序线程,我们仍然可以使用带有volatile变量的竞争条件。 就像下面的代码一样,在一种情况下,写程序线程将x的值检查为零是没有任何上下文切换发生的,而读线程也将x的值视为0。 在一种情况下,编写器线程将x的值检查为零(将x递增1)将其刷新到主内存中(因为x是易失的),发生上下文切换,而读取器线程将x的值视为1。 我只是想知道在这种用例中volatile是否足够,还是我们需要进行同步以避免竞争条件
我尝试执行以下代码,但始终能得到相同的结果
public class VolatileSingleWriterClarity {
static volatile int x = 0;
public static void main(String[] args) {
new Thread(VolatileSingleWriterClarity::writer).start();
new Thread(VolatileSingleWriterClarity::reader).start();
}
public static void reader() {
System.out.println(x);
}
public static void writer() {
x++;
}
}
答案 0 :(得分:1)
就像下面的代码一样,在一种情况下,写程序线程将x的值检查为零可能不会发生上下文切换,而读线程也将x的值视为0。
是的,那绝对是可能的。即使x
是易失性的,x++
涉及两个完全独立的操作:易失性读取,然后是易失性写入。这些操作都是原子操作,但是在它们之间进行上下文切换绝对是可能的。 (两个线程也可以在完全独立的处理器内核上运行,因此即使不进行上下文切换,读者也有可能在写入者即将写入新值的同时读取原始值。 )
我只是想知道在这种用例中,volatile是否足够?还是需要进行同步处理以避免竞争状况
synchronized
并不能真正帮助您。您似乎担心要避免这种情况(volatile
允许但synchronized
可以阻止):
x
的原始值x
的原始值,并将其打印出来x
的新值,该值永远不会被读取但它完全等同于这种情况(volatile
和synchronized
都允许):
x
的原始值,并将其打印出来x
的原始值x
的新值,该值永远不会被读取因此没有固定另一个就没有意义。
如果您要确保读取器线程在写入器线程写入之后才读取x
,则需要做一些更复杂的事情,例如使用wait
和notify
。