java 使用volatile修饰符是线程之间可以共享变量,一个变量用volatile修饰,意味着在多个线程情况下此变量是可见并且是一致的;在特定情况下volatile比锁拥有更好的性能
volatile int count;
volatile 原理
介绍volatile原理之前,先来简单了解下java的内存模型
我们在执行我们的程序的时候,jvm根据自己的内存模型会把内存分为:方法区 Method Area,虚拟机栈VM Stack,本地方法栈Native Method Stack,堆Heap,程序计数器 Program Counter Register
方法区
是被所有的线程共享的一块内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
虚拟机栈
每个方法执行的同时会创建一个栈帧,栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
本地方法栈
本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法服务(也就是字节码),而本地方法栈为虚拟机使用到的Native方法服务。
堆Heap
Java堆是被所有的线程共享的一块内存区域,在虚拟机启动时创建。
程序计数器
程序计数器可以看做是当前线程所执行的字节码的行号指示器
详细参考:https://www.jianshu.com/p/7ebbe102c1ae
volatile数据一致性
从方法区定义可知一个变量count声明为volatile类型,则意味这这个变量将存储在方法区;而线程运行时,线程会单独拷贝一份count变量到自己的内存区域,这个内存区域也就是虚拟机栈,画个图
每个线程都拷贝了一份count变量到自己的内存区域,那是怎么做到一致性的?
在多线程情况下,如果某一个线程要对volatile 变量修改,首先运行该线程的cpu会锁定方法区变量内存区域,保证做到数据修改的原子性;那现在问题就来了,其他线程是怎么获得最新的数据?运行其他线程的cpu有会嗅探总线上该内存区域的地址是否被修改;如果该线程缓存的变量副本所指向方法区的地址发生了变化,则将自己缓存的数据设置成无效,等待线程使用到该变量的时候,会从新从方法区获得一份新的数据,同步到本地线程的缓存区域,这样就volatile变量就做到了多线程的可见以及一致性