volatile关键字分析

关于线程的可见性

什么是线程间的可见性?
一个线程对共享变量值的修改,能够及时的被其他线程看到。

什么是共享变量?
如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。

什么是java内存模型?(Java Memory Model,简称JMM)
JMM描述了java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。

  1. 规则1:
    1>所有的变量都存储在主内存中
    2>每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)
  2. 规则2:
    1>线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写
    2>不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量的传递需要通过主内存来完成

示例代码

public class VisableDemo {
//volatile 解决可见性问题
  public volatile static boolean stop = false;

  public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(()->{
      int i = 0;
      while (!stop){
        i++;
      }
      System.out.println("result:"+i);
    });

    thread.start();
    System.out.println("begin start thread");
    Thread.sleep(10000);
    stop = true;

  }

}

Lock指令的作用:

  • 将当前处理器缓存行的数据写回到系统内存
  • 这个写回内存的操作会使在其他cpu里缓存了该内存地址的数据无效

什么时候需要用volatile?

当存在多个线程对同一个共享变量进行修改的时候,需要增加volatile,保证数据修改的实时可见。

指令重排序会导致运行顺序发生变化,如下图:


volatile关键字分析_第1张图片
image.png

这两个方法运行顺序有可能不是顺序进行的,有可能会发生exeToCPU1()先执行,造成了value的值计算出现差错。

为了避免这种问题出现,cup层面做了处理:
  • Store Barrier :强制所有在store屏障指令之前的store指令,都在该store屏障指令执行之前被执行,并把store缓冲区的数据都刷到CPU缓存
  • Load Barrier :强制所有在load屏障指令之后的load指令,都在该load屏障指令执行之后被执行,并且一直等到load缓冲区被该CPU读完才能执行之后的load指令
  • Full Barrier :复合了load和store屏障的功能

内存屏障


volatile关键字分析_第2张图片
image.png

你可能感兴趣的:(volatile关键字分析)