volatile有序性的真正作用

中心思想

使普通全局变量的写对其他线程立即可见(使用volatile有序性来传递)

内存屏障

先来一堆有必要的废话

  • LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
  • StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
  • LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
  • StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。

Java内存模型允许编译器和处理器对指令重排序以提高运行性能,并且只会对不存在数据依赖性的指令重排序。

为了实现volatile的有序性内存语义(jdk5之后),编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

  • 在每个volatile写操作的前面插入一个StoreStore屏障。
  • 在每个volatile写操作的后面插入一个StoreLoad屏障。
  • 在每个volatile读操作的前面插入一个LoadLoad屏障。
  • 在每个volatile读操作的后面插入一个LoadStore屏障

volatile写操作插入内存屏障后生成的指令序列如下图所示。

volatile读操作插入内存屏障后生成的指令序列如下图所示。

传递性 :如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。

相信大家对上面的内容很熟悉了,但是代表啥意思呢,估计你还是一头雾水。我们举个例子

int e = 0;
volatile f = 0;


//thread 1
e = 1;    //操作 A
f = 1;    //操作 B

//thread 2

int j = f;   //操作 C
int k = e;    //操作 D

我们假设 thread 1 执行结束之后thread 2执行,由于f是volatile变量,那么可知B操作的写,对于C操作的读是可见的。那么可得B先发生与C,每个线程单独来看, A先发生与B, C先发生与D,最后我们再加上传递性可知。

A->B->C->D

至此我们可以得到普通变量e的的写入对于其他线程立即可见(注意变量f在其中起到的作用)

Reentrantlock 也借助了volatile的这个特性

总结一下有序性的含义

  1. 禁止指令重排
  2. volatile写会将线程工作缓存(cpu缓存)中的所有数据写入主存
  3. volatile读会将线程工作缓存(cpu缓存)中的所有数据失效,读的时候需要从主存中取。

测试代码

前面举的例子比较难测试出反例(对普通变量的写,不通过volatile的有序性保证,其他线程不是立即可见),所以写了下面的测试代码。

    static int a = 0;
    static volatile int b = 0;  //去掉volatile修饰会发生死循环,即变量a对于其他线程不是立即可见


    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while(a==0) {
                int c = b;
            }
        });
        thread.start();

        Thread.sleep(200);

        new Thread(() -> {
            a = 1;
            b = 1;
        }).start();
        
        thread.join();
    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值