JAVA 并发机制的底层实现原理之volatile

1 、volatile 的应用

在多线程并发中volatile 是为了保证共享数据变量的可见性。就是说当两个线程需要同时修改一个共享变量的时候,另外一个线程能够读取到这个修改的值。 并且volatole 会比synchronized 的使用更加的使用成本低,不会导致上下文切换和调度。

2 、 volatile 的原理

如果一个变量被声明为 volatile Java 线程内存模型确保所有的线程看到这个变量是一致的。

之所以要使用到volatile 来声明变量是因为 cpu 在处理数据的时候无法达到数据的一致性,存在高速缓存和重排序。所以在此之前需要了解CPU 的术语定义

术语术语描述
内存屏障是一组处理器指令,用于实现对内存操作的顺序限制
缓冲行缓存中可以分配的最小存储单位,处理器填写缓存时会加载整个缓存线,需要使用多个主内存读周期
原子操作不可中断的一个或者一系列的操作
缓存行填充
缓存命中如果进行高速缓存进行填充操作的内存位置仍然是下次处理器访问的地址时,处理器从缓存中读取的操作位,而不是从内存读取
写命中当处理器操作数写到一个内粗缓存的区域时,它首先会检查这个缓存的内存地址是否在缓存行中,如果存在一个有效的缓存行,则处理器将这个操作写回到缓存,而不是写回到内存
读命中一个有效的缓存行被写入到不存在的内存区域

hsdis 可以通过以下链接查看生成汇编指令来查看 volatile
链接:https://pan.baidu.com/s/1oEe2KQSf1Pe_MNMV4zNcWg
提取码:z8rz

修改运行指令
在这里插入图片描述

public class main {
       static  volatile  boolean flg = false;
    public static void main(String[] args) throws InterruptedException {
            Thread tq  =new Thread(() ->{
               int i = 0;
               while (!flg){
                   i++ ;
               }
                System.out.println(i);

            });
            tq.start();
            Thread.sleep(100);
            flg=true;
    }
}

volatile 在修饰共享变量是进行操作可以在控制台上看到 lock 的一汇编指令。在这里插入图片描述
lock 表示
1) 当前处理器缓存行的数据协会到系统内存
2) 这个写回内存的操作会使得在其他的CPU 里缓存了该内存地址的数据无效。(CPU 存在三种缓存 L1 /L2/L3)
在这里插入图片描述
MESI(缓存一致性协议 硬件的处理方式)
为了提高处理的熟读,处理器不直接和内存进行通信,而是将系统内存的数据读取到缓存中(L1,L2,L3)后在进行操作,但是操作玩不知道何时会写入内存,如果声明了volatile 的变量进行写入操作,JVM 就会直接向处理器发送一条lock 的前缀指令,将这个变量所在的缓存行写道系统内存。但是在多处理器的情况下,其他处理器的缓存值还是旧的,就会出现缓存一致性。所以在缓存一致性的协议,每个处理器通过嗅探在总线上传播的数据检查自己的数据是否过期。当自己的的缓存对应的内存进行修改过的时候就会把缓存数据设置为无效(invalid )。 会重新从系统内存把数据读取到缓存中。

对于JMM 内存模型(内存屏障)

内存屏障 是一组处理器指令,用于实现对内存操作的顺序限制
对于使用了volatile 的属性 在jmm 层面会加上一个全屏障的操作。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值