volatile解读

要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。

用volatile修饰共享变量之后会发生如下变化:

第一:使用volatile关键字会强制将修改的值立即写入主存;

第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);

第三:由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取。

注意:修改共享变量后,会影响另一个线程的读取。如果第一个线程只是读取共享变量,那么就不影响另一个线程去读取。这一点很重要。虽然volatile能保证可见性,但保证不了原子性。类似于i=i+1,这种非原子操作,用volatile修饰也是没用的。只有boolean类型用volatile修饰才是有用的。因为xxx=false是原子操作,不需要读,是直接写,那就影响另一个线程的读写操作。一旦有修改,volatile变量在别的线程中就要重读。当然如果两个线程同时读取到一个变量(boolean型),这个时候又各自进行,一个修改,另一个做一次判断(同时),那么修改后,只要另一个线程没有再去判断,那么这个含判断的线程用的还是之前的,这个是没办法的,除非用锁去保证。

因为volatile保证了可见性,所以不会拷贝到工作线程,而是直接从主存中获取。另外final是要去拷贝一份到其它工作线程中的,所以两者是冲突的,所以volatile和final不能一同使用。

volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性。

举个例子:

//x、y为非volatile变量
//flag为volatile变量  
x = 2 ;        //语句1
y = 0 ;        //语句2
flag = true //语句3
x = 4 ;         //语句4
y = - 1 ;       //语句5
由于flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面,也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的。并且volatile关键字能保证,执行到语句3时,语句1和语句2必定是执行完毕了的,且语句1和语句2的执行结果对语句3、语句4、语句5是可见的。
作用举个例子:
//线程1:
context = loadContext();   //语句1
inited = true ;             //语句2
 
//线程2:
while (!inited ){
   sleep()
}
doSomethingwithconfig(context);

如果inited没有volatile修饰,那么有可能语句2会在语句1之前执行,那么久可能导致context还没被初始化,而线程2中就使用未初始化的context去进行操作,导致程序出错。这里如果用volatile关键字对inited变量进行修饰,就不会出现这种问题了,因为当执行到语句2时,必定能保证context已经初始化完毕。

-----------------------------------------------

volatile的应用场景有两个:

1、就是

//线程1:
context = loadContext();   //语句1
inited = true ;             //语句2
 
//线程2:
while (!inited ){
   sleep()
}
doSomethingwithconfig(context);这个例子
2、懒汉模式的双重检查
class Singleton{
     private volatile static Singleton instance = null ;
 
     private Singleton() {
 
     }
 
     public static Singleton getInstance() {
         if (instance== null ) {
             synchronized (Singleton. class ) {
                 if (instance== null )
                     instance = new Singleton();
             }
         }
         return instance;
     }
}
---------------------------------------------------
下面与上面无关,只是临时想到的,单例模式最好的就是静态内部类的方式
  1. public class Singleton {  
  2.     static class SingletonHolder {  
  3.         static Singleton instance = new Singleton();  
  4.     }  
  5.       
  6.     public static Singleton getInstance(){  
  7.         return SingletonHolder.instance;  
  8.     }  
  9. }  




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值