如果我省略了Java的volatile关键字会发生什么?
如果我省略了Java的volatile关键字会发生什么?
这个问题已经在这里有答案了:
我刚学习了Java中的volatile
关键字。
实际上,在一个CPU中读取或写入变量时,它会保存在该CPU的高速缓存中,但不一定会立即写入内存。
在某些情况下,我会将对象引用或原始变量传递给另一个线程,但我尚未使用volatile
关键字,因为我直到现在才了解该关键字。
我认为,如果一个新的线程第一次读取该变量,则没有问题。然而,如果我的理解是正确的,那么如果第二个线程更改了该变量,那么第一个线程的CPU可能会将其保存在缓存中并报告一个过时值。省略volatile
关键字的影响是这个问题吗?
示例:
- 线程A将对象的变量值设置为
\"First\"
。 - 线程B第一次读取该变量的值。
- 线程A将变量的值更改为
\"Second\"
。 - 线程B不久之后再次读取该值,但由于CPU缓存,它仍然报告
\"First\"
。
这是省略volatile
关键字时的主要后果吗?线程报告一个过时值?
我的理解正确吗?此外,对于被另一个线程访问的非final变量,什么情况下不需要使用volatile
关键字,我也接受其他建议。我知道何时使用它,但我需要很好地理解何时不使用它。
admin 更改状态以发布 2023年5月24日
这涉及到Java内存模型,以及一个线程如何观察另一个线程。在单个线程内,执行的操作效果按照它们的书写顺序进行。如果另一个线程观察由一个线程修改的变量,那么第二个线程可能看到变量的修改顺序与第一个线程执行它们的顺序不同。这可能是因为缓存或编译器指令重排的缘故。
同步块包括内存屏障,它将CPU缓存写入内存,而编译器知道不重新组织代码以使东西跨越同步块边界移动,因此在同步块之前发生的任何事情对观察线程都是可见的。
访问volatile变量也包括内存屏障,所以如果一个线程写入一个volatile变量,任何读取该变量的线程都将读取最新写入它的值。
因此,通常情况下,对非volatile变量所做的修改在进入同步块之前可能对另一个线程不可见。对volatile变量所做的修改会立即可见。