线程安全1.2(内存可见性问题)

public class demo1 {
    private static int count=0;
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
           while(count==0){

           }
           System.out.println("t1线程结束");
        });
        Thread t2=new Thread(()->{
            Scanner scanner=new Scanner(System.in);
            System.out.print("请输入一个整数:");
            count= scanner.nextInt();
        });
        t1.start();
        t2.start();
    }
}

通过上述代码,我们可以发现预期结果是线程t2在输入一个非0的数字后程序会结束,但实际运行结果是不会结束,卡住了

分析一下为什么会导致这种结果出现:
在这里插入图片描述
在执行循环体的时候会将成员变量加载到cpu中,而从内存读取数据到cpu相对于cpu中的cmp来说执行速度是非常慢的,所以在cmp执行很多次后感受到cmp的内容并没有变化,于是就发生了编译器优化,只是在第一次进行了真正的load,后续代码执行到t2时就不再去load,用的就是第一次load的值。

如何解决内存可见性问题:
1.使用关键字volatile,
volatile的注意事项:
1.只可以对变量进行修饰,不可以对方法进行修饰。
2.不可以对方法中的局部变量进行修饰

   private volatile static int count=0;

这个关键字就是告诉编译器,不要触发上述优化(具体在java中,是让javac生成字节码的时候产生了“内存屏障”相关指令)

jvm中上述问题是这么表达的:
当t1执行的时候,要从工作内存中读取count的值,而不是从主内存中
后续t2修改count,也是会先修改工作内存(工作存储区(cpu寄存器+缓存)),同步拷贝到主内存。但是由于t1没有重新读取主内存,导致最终t1没有感知到t2的修改

synchronized(锁)和volatile的理解:
首相这两者是没有任何关系的,对于sychronized是将代码中的非原子性指令打包成一个整体,防止由于线程之间相互竞争特性而导致指令的执行顺序发生错误,导致代码bug。而volatile是告诉编译器,此处不要进行优化防止代码优化而出现bug。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值