为了账号安全,请及时绑定邮箱和手机立即绑定

volatile解析

标签:
Java

volatile是java提供的一种轻量级的同步机制,可以理解为一个变量的同步锁。相比于重量级锁synchronized而言,synchronized大部分时候都是锁的方法或者代码块,而volatile只是锁一个变量,所以volatile更加轻量,当然现在jdk对synchronized的性能越来越优化,也没有想象中的那么重,在平时需要保证一个方法线程安全时,可以放心的使用synchronized。

原理

计算机系统在进行计算时,cpu会从内存中读取数据缓存在自己的寄存器(cpu中空间很小的一块内存空间,方便取值计算,不用每次都读取内存)中,现在大部分计算机都是多核计算机,有多个cpu,这里的寄存器对其他cpu是不可见的,如下图

1577063433170

当把一个变量声明为volatile类型后,这个变量不会被缓存在cpu的寄存器中,每次都是直接操作的内存空间,因此其他线程每次读取的都是最新的值。

特性

  • 变量可见性:volatile变量对所有线程都是可见的,一个线程修改了变量的值,那么其他线程会立即获取这个新值。
  • 禁止指令重排序:在jvm编译器和cpu中,有时候会为了优化效率会对正常的操作指令进行重新排序,volatile变量会禁止指令重排序。

举例

我们熟悉的单例模式中,有一种安全的写法,如下双重检查的写法

public class Single {

    private static volatile Single single = null;

    private Single() {
    }

    public static Single getInstance() {
        if (single == null) {
            synchronized (single) {
                if (single == null) {
                    single = new Single();
                }
            }
        }
        return single;
    }
}

代码中将Single对象声明成了volatile对象,如果没有volatile会出现什么情况呢?我们看一下single = new Single()这句代码,正常的操作会是这样:

  1. 分配内存地址M;
  2. 在内存M上初始化Single对象;
  3. 将M的地址赋值给single对象;

但编译期会出现指令重排,操作会变成这样:

  1. 分配内存地址M;
  2. 将M的地址赋值给single对象;
  3. 在内存M上初始化Single对象;

回到代码中,当A线程执行single = new Single()中的第二步时,B线程进入getInstance()方法,先判断 if (single == null),这时single对象上已经有内存地址了,B线程会直接返回single对象,但是这个线程拿到的是个空对象,内存M上还没有初始化对象。

将single变量声明成volatile时,就会避免这类指令重排的问题。

结论

当我们程序中出现可能多个线程操作同一个共享变量时,要保证这个共享变量的线程安全,可以将这个变量声明成volatile。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
0
获赞与收藏
2

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消