voltile关键字
前提:JVM存在JIT(即时编译器)优化,对于热点代码会存放在CPU缓存中。我们平时用的静态变量和成员变量存放在堆内存中,也就是所说的主存,是线程共享的。某个线程运行时JVM会申请一片栈内存,栈内存又由栈帧组成,栈帧就是为每个线程中的每个方法开辟的内存空间,然而由栈帧组成的栈内存是线程私有的,也就是所说的工作内存。当一个线程while(true)的使用静态变量的时候,即便你其他线程改变了这个变量的值,但是在这个线程中这个变量依然没有改变。
因为其他线程改变这个静态变量的时候改变的是主存的值,然而当前线程去获取值的时候没有去缓存拿这个新值而是去CPU缓存里面拿的旧值。这就有点类似于redis缓存和数据库数据不一致的问题。解决办法就是在申明静态变量的时候加一个voltile关键字从而保证共享变量的可见性(一个线程对共享变量修改后对其他线程是可见的,也就是其他线程获取值也是最新的),加了voltile后就不会走缓存去获取旧值而是直接从主存中去获取最新值。
除了voltile外,synchronized 语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是 synchronized 是属于重量级操作(产生也对象关联的monitor),性能相对更低。