并发编程基础之volatile
volatile
1、volatile
保证多线程数据的可见性
2、机器硬件CPU与JMM
(1) CPU 缓存模型


程序的局部执行原理
(2) CPU缓存一致性问题
每个CPU修改内存数据的步骤
- 1、从内存中把数据读到cache中,并放到寄存器中进行操作
- 2、在cache中更新数据
- 3、把更新的结果刷新到内存中
一个CPU读数据,进行操作,另一个CPU写数据,就会产生数据不一致问题。
解决方案
- 1、总线加锁
地址总线 数据总线 控制总线,对总线进行加锁时,其他CPU无法进行使用,会造成效率低。
- 2、MESI缓存一致性协议
a、读操作:不做任何操作,把cache中的数据读到寄存器
b、写操作:发出信号,通知其他CPU,将该变量的CacheLine置为无效状态,其他CPU要访问这个变量的时候,只能从内存中获取。
Cache line 是cpu的一种实现机制,CPU的cache中会增加很多的Cache line。
(3)、java内存模型

- 主内存中的数据所有线程都可以进行访问(共享数据)
- 每个线程都有自己的工作空间(本地内存)(私有数据)
- 工作空间数据:局部变量、内存的副本
- 线程不能直接修改内存中的数据,只能读到工作空间来修改,修改完成后刷新到内存
3、Volatile关键子的语义分析
volatile作用
让其他线程能够马上感知到某一线程对某个变量的修改
当一个线程对volatile修饰的变量进行修改时,会通过JMM控制向其他线程发出信号,映射到硬件中就是使Cache line置为无效
保证可见性
对共享变量的修改,其他线程马上能感知到,不能保证原子性。
多个原子性操作合在一起,就不存在原子性
public class Increa {
static volatile int i = 0;
public static void incre() {
i++;
}
public static void main(String[] args) {
for (int j = 0; j < 10; j++) {
new Thread(() -> {
for (int k = 0; k < 5; k++) {
incre();
}
}).start();
}
System.out.println(i);
}
}
//这里输出不是50,证明volatile不能保证原子性,i++操作为非原子操作
保证有序性
禁止重排序
重排序(编译阶段,指令优化阶段)
输入程序的代码顺序并不是实际执行的顺序
++重排序后对单线程没有影响,对多线程有影响++。
对于volatile修饰的变量:
- volatile之前的代码不能调整到它的后面;
- volatile之后的代码不能调整到它的前面(as-if-seria);
- volatile修饰的代码位置不变化;
volatile的原理和实现机制
使用hsdis汇编工具 反编译
java->class->JVM->ASM文件(汇编文件)
volatile int a=0;
代码映射到汇编语言
Lock:a

总结:java中volatile具有的功能:
- 1.可见性。
- 2.防止JIT或者java解释器对指令重排序。
- 3.内存屏障的功能,java解释器遇到volatile变量,会在volatile变量赋值之后,加一个lock addl $0x0,(%rsp)具有内存屏障功能的指令,防止内存重排序。
4、volatile的使用场景
状态标志(开关模式)
public class ShutDowsnDemmo extends Thread{
private volatile boolean started=false;
@Override
public void run() {
while(started){
dowork();
}
}
public void shutdown(){
started=false;
}
}
双重检查锁定(double-checked-locking)
public class Singleton {
private volatile static Singleton instance;
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
instance=new Singleton();
}
}
return instance;
}
}
需要利用顺序性
5、volatile与synchronized的区别
(1)使用上的区别
Volatile只能修饰变量,synchronized只能修饰方法和语句块
(2)对原子性的保证
synchronized可以保证原子性,Volatile不能保证原子性
(3)对可见性的保证
都可以保证可见性,但实现原理不同
Volatile对变量加了lock,synchronized使用monitorEnter和monitorexit monitor JVM
(4)对有序性的保证
Volatile能保证有序,synchronized可以保证有序性,但是代价(重量级)并发退化到串行
(5)其他
synchronized引起阻塞
Volatile不会引起阻塞

浙公网安备 33010602011771号