深入理解并发编程系列-volatile的作用

共享模型之内存

可见性

由于编译器优化,jvm会对多次从内存中读到的数据加载到缓存中,下次读取会直接从缓存中读取

因此当main线程对内存中的数据改写后,thread线程依然读到的是缓存中的数据,导致没办法退出循环。

static booleen run  = true;

Thread thread = new Thread(()->{
	while(run){
        if(run==false){
            break;
        }
    }  
});

thread.start();
sleep(1);    
run = false;

可见性解决

可以使用synchronized来解决这个问题,synchronized中的赋值代码会同步到内存中。

也可以使用volatile解决,用volatile修饰的变量修改后会同步内存中。读取也会从内存中读取

指令重排序

jvm会对jvm指令进行重排序来提高性能。指令重排序的原则是不会影响运行结果,但是当多线程情况下便会出现问题

解决可以用volatile解决
原理 volatile 修饰的变量,在读取操作前会加读屏障,使后面的代码对读取操作都是读取到的内存中的值。而在对volatile的变量进行写操作时,会增加写屏障, 保证写屏障之前所有的写操作都会同步到内存中。

读屏障会保证读屏障后的代码不会重排序到读屏障前面

写屏障会保证写屏障前的代码不会重排序到写屏障后面

double-checked-locking (dcl )

private static object instance = null;
private object getinstance (){
	if(instance == null) {
        synchronized(object.class) {
            if(instance == null ) {
                instance =  new object();
            }
        }
    }
	return instance;
    
}

    

上述代码是有问题的如果第一个线程执行到instance = new object()这一步,在jvm指令上有两步,先调用object的构造方法,在赋值给instance 但是如果发生指令重排序 问题,就会导致先赋值后调用构造方法,如果赋值后还没调用构造方法,第二个线程就进入了外层的判断语句,发现instance!=null 这个时候会返回一个空的instance对象,

所以解决方法就是在instance变量上加volatile 让赋值语句和构造方法语句不发生重排序

private static volatile object instance= null;

在synchronized中增加第二次判断是因为,如果两个线程都在赋值前进入了第一个if判断,这时一个阻塞住,一个进入创建对象,如果没加第二个if 就会导致第二个线程进入synchrionized后也创建一个对象,创建了两个对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值