《并发编程实战》2.0第三章笔记volatile关键字

可见性

重排序与失效数据

由于多线程的情况下,某些线程有时候会将一些值缓存起来,读这些缓存而不从主内存中读取所以可能会有问题,它一直在读取一个已经失效的数值这就会导致一些问题(比如下面代码的死循环,还有比如没有线程安全get、set方法阔能读取到更新的值也阔能没读取到,那就很难顶了)。而且一些指令可能会重排序,让结果不像我们预期的那样。

尝试下面这个程序大概率会发现,陷入死循环。

public class Main {
   private  static int number;
   private static boolean flag;
   private  static   class  ReadThread extends Thread{
       @Override
       public void run() {
           while (!flag){};
           System.out.println(Thread.currentThread().getName()+number);
           System.out.println(Thread.currentThread().getName()+"输出");
       }
   }
    public static void main(String[] args) throws InterruptedException {
        new ReadThread().start();
        Thread.sleep(10);
        new Thread(()->{
            flag =true;
            number = 99;
        }).start();
    }
}

非原子操作的64位操作

由于Java虚拟机会将非volatile类型的long和double变量(64位),的读操作和写操作分解为两个32位操作。这会带来一些安全性的问题(比如可能会读取到更新前的高32位和其他线程更新后的低32位之类的)

解决方式

单单使用锁是没有办法解决这种局面的!!那么我们咋办呢!
synchronized+volatile
volatile的含义就说确保将变量的更新操作通知到其他线程,一个变量被声明为volatile类型后,便会告知JVM这个变量是共享变量,就不会被缓存在寄存器或者其他处理器不可见的地方,总是返回最新的写入值。这个关键字相当于范围更小的synchronized操作,读取volatile相当于进入同步代码块,写入则相当于退出,不过比锁要脆弱。
使用它必要条件为:

  1. 对变量的写入操作不依赖与当前值(i++这种就不行)。
  2. 该变量不会与其他状态变量一起纳入不变性条件中(俺理解的是原子性的范围)。
  3. 访问变量时不需要加锁。

且不要滥用它,简化代码实现以及同步策略时才使用,它的作用主要为:

  • 确保自身状态的可见性
  • 确保所引用对象状态的可见性
  • 表示一些重要的程序生命周期事件的发送
   private volatile static int number;
   private volatile static boolean flag;
发布了18 篇原创文章 · 获赞 1 · 访问量 279

猜你喜欢

转载自blog.csdn.net/qq_38732834/article/details/105188352