说说volatile关键字

volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制。

当一个变量被volatile关键字修饰后,它将具备两种特性:

    1、保证此变量对所有线程的可见性。

    2、禁止指令重排序

先来说说第一条特性:

    保证此变量对所有线程的可见性,这里的可见性是指当一条线程修改了这个变量的值,新值对于其他线程来说

    是立即得知的。普通变量是做不到的。普通变量的值在线程间传递需要主内存来完成。例如,线程A修改一个普通

    变量的值,然后回写到主内存,另外一条线程B在线程A回写完成后再从主内存进行读取,新变量值才会对线程B可见。

第二个特性:

    指令重排序是指在不改变运行结果的前提下,对指令进行重排优化。

    比如在下面代码中


    对于上述代码,如果线程1执行write方法,线程2执行multiply方法
    如果线程1进行了指令重排序,即先进行flag=true,在进行a=2
    这时候ret就不是4了,加上volatie关键字后就不会出现这问题了

还有一个就是双重校验锁的单例模式


这段代码看起来很完美,很可惜,它是有问题。主要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
  1. 给 instance 分配内存
  2. 调用 Singleton 的构造函数来初始化成员变量
  3. 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可    能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错

在最后,顺便提一下

    在给变量加上volatie关键字后,然后对该变量进行写操作, 然后查看生成的汇编指令,它在会多出一行Lock汇编代码
    Lock前缀的指令在多核处理器会引发两件事情
    1、将当前处理器缓存行的数据写回系统内存
    2、这个写回内存的操作在其他CPU里缓存了改地址的数据无效
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值