java volatile关键字

volatile关键字属于多线程中的内容,用于修饰变量,被volatile修饰的变量在多线程环境下具有可见性,但是无法保证原子性。

可见性:volatile修饰的变量对所有的线程都是可见的,一旦变量值修改了,所有线程都能看见(这句话比较宏观,不够细节)。

指令重排:java代码中,程序是一句一句的,有顺序,运行后会有个结果,但是经过编译之后,可能因为对java代码作了优化,程序的执行不是代码中的顺序,那么指令的执行顺序也就不同,但是最终的运行结果是一样的。单线程内是不会出现指令重排的。

volatile禁止指令重排序的一些规则(这个不好理解,大家可以不看,我只是为了方便记笔记而已):
  1.当第二个操作是voaltile写时,无论第一个操作是什么,都不能进行重排序
  2.当地一个操作是volatile读时,不管第二个操作是什么,都不能进行重排序
  3.当第一个操作是volatile写时,第二个操作是volatile读时,不能进行重排序

CPU 与 内存之间有一个高速缓存,CPU是和高速缓存交互的,如果要读取一个数据,先从高速缓存读,如果没有,再从内存读,缓存一份到高速缓存,CPU再从高速缓存读;如果要修改一个数据,也是先去尝试从高速缓存读到数据,进行修改后,将结果写回高速缓存,由高速缓存器将结果写回内存完成修改。

在多 CPU 情况下,每个CPU都有一个高速缓存,就会造成同一个目标数据,在不同的CPU缓存中不一致。

所以,在多个CPU对volatile变量进行修改时或读取时,要修改数据的CPU肯定是最后要将高速缓存里修改后的新值写回内存,就在此时,CPU知道它是volatile变量,所以写CPU要去竞争一个锁,这个锁可以锁住所有CPU缓存中的volatile数据,拿到锁的CPU才有资格将新值写回内存,其它CPU则不能写回volatile新值了,当内存中的volatile值更新后,所有的CPU都会知道(总线原理)该volatile变量更新了,如果自己的缓存中有该值,说明不新鲜了,舍弃掉,重新去内存中读取新的volatile值,再进行相关的计算。

上述过程就体现了可见性,但凡一个线程对volatile变量进行修改,其他的线程都可以立即看到(一个CPU对于一个正在运行的线程嘛)。

但是无法保证原子性,因为不管是读取volatile变量还是修改volatile变量都分为几步,这几步不是原子性的。

总结:能实现可见性的还有synchronized 和 final 关键字,synchronized 的原理是:对一个变量执行解锁之前,必须先把此变量同步回主存中; final 的原理是:常量是存储在共享内存里的,所有线程都能看见该变量。

volatile关键字在功能上不如synchronized,但是 volatile 的效率比 synchronized 高不少,轻量。 synchronized是万能的,volatile能用的地方,synchronized一定也能用,反之不然。我们要用volatile的时候,需要考虑好volatile是否能满足我们的需求,尽管volatile只能保证可见性,但是有些场景下,还是能用的。

应用场景: 对于volatile,你就记住这个特性,立即可见性,一旦volatile变量值改变了,其它线程都能立即看见,保证信息传递的实时性。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值