主线程对其某个字段所做的变更对新创建出来的线程不可见。造成这种现象的首要原因是,JIT编译器可能对新线程代码里的while循环进行了优化,并因此导致新线程在线程上下文中无法看到变量的变化。此外,新线程可能会只从其寄存器或本地cache中读取标记变量的值,而不是每次都跑去速度更慢的内存里进行操作。基于上述原因,新线程就无法看到主线程对其标记变量值的变更了,
如果想要快速修复此问题,只需要将变量done标记为volatile就可以了。
关键字volatile的作用是告知JIT编译器不要对被标记变量执行任何可能影响其访问顺序的优化。该关键字警告JIT编译器,该变量可能会被某个线程更改,所以任何对该变量的读写访问都需要忽略本地cache并直接对内存进行操作。之前我将这个改动称为快速修复,是因为如果我们将所有变量都标记为volatile的话,虽然可以完全规避此类问题,但却会使每次变量访问都要跨越内存栅栏并最终导致程序性能下降。此外,在多个字段被多个线程并发访问的场景下,由于针对每个volatile字段的访问都是各自独立处理的,并且也无法将这些访问统一协调成一次访问,所以volatile关键字无法保证整体操作的原子性。该问题所造成的后果是,线程很可能对某些字段只能看到其中间结果,而对另一些变量则看到的是最终的变更结果。
总结:
- volatile关键字修饰的字段会保证内存可见
- volatile关键字修饰的字段不会进行指令重排
网友评论