线程安全之可见性揭秘-《云课堂》

4 篇文章 0 订阅

java 内存模型 (jmm)和jvm运行区区别

java内存模型是Java语言规范(提出规则) 描述多线程程序的规则
规范了Java虚拟机与计算机内存是如何协同工作的。Java虚拟机是一个完整的计算机的一个模型,因此这个模型自然也包含一个内存模型——又称为Java内存模型(用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。)。参考http://ifeve.com/java-memory-model-6/ https://www.jianshu.com/p/15106e9c4bf3
jvm运行区(具体体解决规范)就是堆,方法区,栈

多线程中的问题:

  1. 所见非所得
  2. 无法肉眼去检查程序的准确性
  3. 不同的运行平台有不同的表现
  4. 错误很难重现

所见非所得问题如下代码:
public class Demo1Visibility {
int i = 0;
boolean isRunning = true;

public static void main(String args[]) throws InterruptedException {

    Demo1Visibility demo = new Demo1Visibility();

    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("子线程here i am...");
            while(demo.isRunning){
                demo.i++;
            }
            System.out.println(demo.i);
        }
    }).start();

    Thread.sleep(3000L);
    demo.isRunning = false;
    System.out.println("主线程shutdown...");
}

}

预想结果为:
子线程here i am…
主线程shutdown…
2125892746
真实结果为:
子线程 here i am...主线程shutdown...
其调整不同的jdk值其i的打印值为:
在这里插入图片描述
我们可以看到【i】的值没有打印,而且线程还没有执行结束,那是为什么呢? 那我们一起来一步一步的分析推理下,我们先把JMM逻辑图画一下,如下图:
在这里插入图片描述

  1. 主线程main和子线程是默认读取主内存中isRunning=true
  2. main更改其isRunning=false
  3. 分析知要吗就是主线程的isRunning改变的值没及时存入,要么就是子线程没立刻读取到内存变化的值。
  4. 判断是否是cpu高速缓存的原因吗?由于主线程睡眠了3秒(我们都知道CPU的高速缓存运行速度比内存要快的多)所以排除CPU的高速缓存原因
    因。

我们先分析该代码执行过程图:
在这里插入图片描述
通过上面的分析知道出现与预期的结果不一样的是jit编译器的原因。通过云课堂的学习我们知道 JIT编译器在执行的时候会 遵循as-if-serial语义
会对代码进行指令重排。

指令重排如下图:

在这里插入图片描述
如上图单独一个线程的其值是不会变的,但是2个现场的时候就矛盾了。

解决方案

我们这里用到关键字volatile(保证修饰的值可见性,使其修改的值永远都是取到最新的值)
volatile boolean isRunning = true;
在这里插入图片描述
其原理我们先用运行上面实例.claas进行反编译 javap -v -p Demo1Visibility.class
可以看大下面有这个代码

在这里插入图片描述
我们看到 用volatile修饰的isRunning变量反编译后 看到访问控制加了个ACC_VOLATILE标识符
查看oracle虚拟机https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2
在这里插入图片描述
我们可以看到ACC_VOLATILE的作用就是不允许JIT编译器进行缓存到此我们也整理下volatile关键字吧

  1. 可见性问题:让一个线程对共享变量的修改,能够及时的被其他线程看到。
  2. java内存模型规定:
  3. 对volatile变量v的写入,与所有其他线程后续对v的读同步
    要满足这些条件,所以volatile关键字就有这些功能:
    禁止缓存: volatile变量的访问控制符会加个 ACC_VOLATILE
    ————————————————
    版权声明:本文为CSDN博主「weixin_41357524」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_41357524/article/details/104629010
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值