volatile

volatile是什么

volatile是 java提供的一种轻量级同步机制。volatile变量并不保证原子性,因此volatile并不保证线程安全。

volatile关键字有两个作用

1.禁止指令重排序

2.保证可见性

什么是指令重排

jvm在编译代码时,或者cpu在执行jvm字节码时,会对现有指令进行重排序。重排序的目的,是在不影响执行结果的情况下,提高程序运行效率。但是这里的不改变结果是指单线程的情况下,但是对于多线程情况下就会出现共享资源的同步问题。

volatile是如何实现上述两条作用的

原因在于jvm帮助我们在volatile变量的读写操作前后插入了指令屏障(也叫栅栏,具体指令屏障的定义及分类可自行google),内存屏障让volatile读写操作前后的操作禁止和volatile读写操作进行重排序。

volatile关键字为什么不能保证原子操作

比如 ,我们知道i++操作是不具备原子性的,被volatile关键字修饰的i,进行i++操作 这个操作jvm指令可以分为3步

1.从内存中读取i的值到工作内存

2.i+1

3.将修改过的工作内存中的值刷新到主内存

加入有两个线程,线程1,读取了i的值到工作内存然后修改了i的值为10,此时cpu时间片用完了让出了cpu,线程1被阻塞;此时线程2得到了cpu时间片读取i为10、修改、并将i的值刷新回主存,此时主存中的i为11,然后线程1继续执行将i的值刷新回主存,主存中的值为11。而我们期望的值为12。

 

 

volatile关键字的典型应用场景-双重检测单例模式

 

class Singleton3 {

private volatile static Singleton3 singleton;

private Singleton3(){

}

public static Singleton3 getSingleton(){

if(singleton==null){

synchronized (Singleton3.class){

if(singleton==null){

//伪代码

// 1.为新对象分配内存空间

//3.将 singleton3指向 新对象的内存地址

// 2.初始化对象

singleton=new Singleton3();

}

}

}

return singleton;

}

}

双重检测单例模式之所以不安全就是因为,可能会发生指令冲排序,而volatile关键字禁止指令重排序的功能正好解决了这个问题

上面伪代码中正常执行的顺序应该是1,2,3 。而进行指令冲排序后可能的执行顺序变为1,3,2这是因为2,3两步指令重排单线程下并不影响结果。

假如有线程A和线程B,线程A走到

singleton=new Singleton3();

这行代码时发生了指令重排序,此时走到了第3步

3.将 singleton3指向 新对象的内存地址

 

而第二步

// 2.创建新对象

还未执行。此时线程B走到第一次判断

if(singleton==null)

 

由于已经分配了内存地址,因此判断为假(我们知道引用类型的对象实际上是存了一个引用在栈里,那么肯定不会判断singleton为空了),此时线程

B拿一个还没创建好的对象去操作,那么肯定是会出问题的。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值