可见性:

存在的问题:

main 线程对 run 变量的修改对于 t 线程不可见,导致了 t 线程无法停止:

  1. static boolean run = true;
  2. public static void main(String[] args) throws InterruptedException {
  3. Thread t = new Thread(()->{
  4. while(run){
  5. // ....
  6. }
  7. });
  8. t.start();
  9. sleep(1);
  10. run = false; // 线程t不会如预想的停下来
  11. }

程序不会停止

1.初始状态, t 线程刚开始从主内存读取了 run 的值到工作内存

1646913001483.png

2.因为 t 线程要频繁从主内存中读取 run 的值,JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中,

减少对主存中 run 的访问,提高效率

1646913048388.png

3.1 秒之后,main 线程修改了 run 的值,并同步至主存,而 t 是从自己工作内存中的高速缓存中读取这个变量

的值,结果永远是旧值

1646913067772.png

解决:

添加volatile修饰符:(只能保证可见性,不能保证原子性)
  1. **注意:**
  2. 想要保证原子性还需要使用synchronized或者ReentrantLock
  3. synchronized也可以保证可见性,但是性能比较低,底层依赖于monitar

它可以用来修饰成员变量和静态成员变量

他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存


有序性:

JVM会在不影响正确性的前提下,可以调整语句的执行顺序

重排序可能导致程序的运行结果与预期结果不一致

使用volatile可以禁止掉重排序