并发面试题:volatile关键字有什么作用?

volatile关键字有什么作用?
第一个作用就是:可以保证多线程环境下的共享变量可见性问题
第二个作用就是:通过增加内存屏障防止多个指令之间的重排序

可见性:是指当一个线程对共享变量进行修改时,其他线程可以立刻看到修改后的值,其实可见性问题本质上是由几个方面造成的,第一方面是cpu里面的高速缓存,在cpu里面设计三级缓存去解决cpu运输效率和内存IO效率的问题,但是它所带来的就是缓存一致性问题,在多线程并行的条件下,缓存的一致性问题就会导致可见性问题。所以对于增加了一个volatile关键字修饰的变量,JVM虚拟机会自动增加#Lock汇编指令。而这个指令会根据不同的cpu型号,会自动添加总线锁或者缓存锁。

简单说下这两种锁:第一个是总线锁,它锁定的是cpu的前端总线,从而去导致同一时刻,只能有一个线程和内存通信,这样就避免了多线程并发造成的可见性问题。第二个是缓存锁,缓存锁是对总线锁的一个优化。因为总线锁会导致cpu的使用效率大幅度下降,所以缓存锁只针对cpu三级缓存中的目标数据进行加锁,而缓存锁是使用MESI缓存一致性协议系统来实现的。

第二个是指令重排序,所谓重排序就是说指令在编写的顺序和执行的顺序是不一致的,从而在多线程环境下导致可见性问题。指令重排序本质上是一种性能优化的手段,它来自于几个方面。首先第一方面是cpu层面,针对于MESI协议的进一步的优化去提升cpu的利用率,所以它引入一个叫storeBuffer的一个机制,而这种优化的机制,会导致cpu的乱序执行,当然为了避免这样的问题,cpu提供了内存屏障指令。上层应用可以在合适的地方去插入内存屏障去避免cpu指令重排序的一个问题。第二个方面是编译器层面的优化,编译器在编译过程中,在不改变单线程语义和程序正确性的前提下,对指令进行合理的重排序,从而去优化整体的一个性能。所以对于共享变量增加了volatile关键字,编译器层面就不会触发编译器的优化,同时它会在JVM里面插入内存屏障指令来避免指令重排序的问题。当然除了volatile关键字以外,从JDK5.0开始,jvm就使用了一种Happens-Before的模型去描述多线程之间的可见性的一个关系,也就是说如果两个操作系统之间具备Happens-Before的关系,那么意味着这两个操作系统具备可见性的关系,不需要额外考虑增加volatile关键字来提供可见性的保障。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值