volatile与synchronized区别

多线程正常执行的时候,我们说的共享变量,其实每个线程都会在线程内部创建变量的一个副本,线程中操作的其实就是这个副本变量,运算结束后,会同步副本变量与原始变量。

synchronized:同步方法或者代码块,之间的操作保证线程安全,原子性操作;

volatile :保证变量的可见性,但是不保证原子性。

 

volatile和非volatile:

volatile:主要在于保证变量的可见性。

volatile能不用就不用吧,这玩意感觉有些复杂了。

有三个功能:

1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障(volatile修饰的变量)这句指令时,在它前面的操作已经全部完成,并且结果对后可见;

2)它会强制将对缓存的修改操作立即写入主存;

3)如果是写操作,它会导致其他线程中对应的缓存行无效。

而非volatile:不会保证变量可见性,因此其他线程读取的数值就可能不是最新的。

 

volatile的使用场景:适合条件:

1.对变量的写操作不依赖于当前值。
2.该变量没有包含在具有其他变量的不变式中。

模式 #1:状态标志

//flage标志,true关闭,false没有关闭
volatile boolean flage;
public void shutdown() { 
    flage = true; 
}

public void doWork() { 
    while (!flage ) { 
        // do stuff
    }
}

上面代码,如果没有volatile标识,线程1调用shutdown,缓存中flage=true,再将缓存和主内存同步,但是这些不是原子操作的,

这时另外的线程执行dowork方法,取得的值还是false。加上volatile关键词后,一旦flage=true后,会立即同步主内存的值(变量的可见性),这样dowork取得的值就是最新的true,从而保证了变量的原子性。

模式 2:一次性安全发布

在缺乏同步的情况下,可能会遇到某个对象引用的更新值(由另一个线程写入)和该对象状态的旧值同时存在。

private volatile static Singleton instance;     
public static Singleton getInstance(){     
    //第一次null检查       
    if(instance == null){              
        synchronized(Singleton.class) {    //1       
            //第二次null检查         
            if(instance == null){          //2    
                instance = new Singleton();//3    
            }    
        }             
    }    
    return instance;    
}    

上述代码,在instance未使用volatile关键词的情况下分析:

线路a获得运行,第一次检查结果为null,然后进入同步块,第二次检查为null,开始构建对象,并返回这个实例。

在返回这个实例化对象之前,线程b取得运行,检查instance为非null,会直接到最末一句,返回了线程a构建的那个实例。

现在最主要的在于这一句代码:instance = new Singleton();这一步会很为两步来操作,并且是没有先后顺序的,1在堆内存中开辟new Singleton()内存并初始化;2在栈内存中instance指向堆内存地址;如果先执行的是第2步,然后线程b执行了,返回的是非null值,但是这个对象并没有初始化。

现在加上volatile修改词之后,在标记3处:instance = new Singleton(); 1是禁止指令重新排序,此代码先执行对象初始化,再将地址传递给引用,所以不存在instance为一个未初始化的变量;2是instance引用改变后,会立即写入主内存,对其他线程者是立即可见的。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值