并发编程系列-volatile详解

303 阅读5分钟

并发编程系列-volatile详解

前言

面试过程中,常见的双层校验锁会引发出去使用volatile关键字这个问题点,相关面试官的考察点主要在于volatile对于共享变量的可见性上,小伙伴试着回答下面按这些问题,看下是否能正确回答上来呢

  • volatile关键字的作用是什么
  • volatile是如何实现可见性的(内存屏障)
  • i++为啥不能保证原子性(分为读数据和写数据两个操作)
  • volatile的应用场景
  • Java内存模型是什么

简介

​ Volatile被称为轻量级的synchronize,运行时候开销比synchronize更小,我们知道volatile能够保证共享变量的可见性,禁止指令重排,今天一起研究下关于volatile是如何实现上述所讲的这些功能,首先我们先看一下Java内存模型相关知识。

内存模型

java内存模型,英文全称为Java Memory Model,简称JMM,JMM本身是不存在的,是为了我们方便理解抽象化的一种概念,是一组规则和规范,它定义了程序中各个变量的的访问方式,Java内存模型规定了所有内存变量都存在主存上,每个线程都是有自己的工作内存,线程对变量的操作都必须从主内存中,对变量的操作不能直接在主存中进行,并且线程不能访问其他线程的工作内存。(ps,处理器不直接在内存进行通信,而是先将内存中的数据读取到内存缓存中(硬件上称为cpu的L1,L2缓存)进行操作,这样干的原因是提高速度)

引入的问题

​ 如果一个变量在每个CPU上都存在缓存(多线程情况下读取到自己的工作内存中),出现缓存不一致问题,我们来看下这个例子,如图所示

volatile

上面例子中i并发的时候可以通过以下两个方式去解决

  • 通过在总线上加Lock锁的方式去解决
  • 缓存一致性协议

volatile变量内存可见性是通过内存屏障实现的,内存屏障其实就是一组cpu指令。当我们对声明成一个volatile变量进行写操作,JVM底层会在对volatile共享变量的写操作加上lock前缀指令。我们来看一下这个lock指令

lock指令

​ 在早期奔腾,inter等处理器上,lock前缀会让处理器执行的时候产生一个lock#信号将总线进行锁定,其他CPU对内存读写请求会被阻塞,一直等到锁释放,后来的处理器逐渐使用缓存一致性协议(MESI)取代了这种方式,因为锁总线期间其他CPU无法访问内存,效率比较低。

缓存一致性协议

​ 平常我们大多数计算器使用的缓存一致性协议都属于嗅探协议,所有内存的传输都是发生在一条共享总线上,所有的cpu都能看到这条总线,cpu除了不断嗅探总线上的数据进行数据交换,还会跟踪其他CPU缓存在做什么,只要CPU处理器将数据写入内存,其他CPU处理器感知之后就会将自己内存中缓存段设置为失效状态,使用的时候去主内存中取读。volatile变量就是通过这样的机制使得每个线程都能获取该变量的最新值。

内存屏障作用

​ 内存屏障两个作用(如果我们变量使用了volatile修饰,就会在读数据的时候插入读屏障,可以让缓存中的数据失效,让从主内存中读。在写指令之前插入写屏障,让写入缓存的最新数据写入主内存)

  1. 先用这个内存屏障的指令必须先执行,后于这个内存屏障的指令必须后执行
  2. 内存可见

happen-before

happen-before关系是java内存模型中保证多线程操作可见性机制。简单来说就是决定变量对你是否可见的,是一个模糊的可见性定义,有如下表现形式

  • 线程内执行的每一个操作都保证了happen-before后面的操作,这保证了程序书写的顺序规则
  • 对于volatile变量,对于写操作,保证happen-before在随后的对该变量的读取操作(这样当我们对volatile变量写的时候,其他变量读取缓存值就会失效)
  • 对象构建完成,保证了happen-before于fiazlize开始动作

来个例子

//x、y为非volatile变量,z为volatile变量
x = 2;        //语句1
y = 0;        //语句2
z = true;     //语句3
x = 4;         //语句4
y = -1;       //语句5

由于flag变量是volatile变量,在进行指令重排序过程中,不会将语句3放到语句1和2的前面,同时也不会将语句3放到4和5的后面,执行3的时候,1,2必须执行完毕且1,2的结果对于3,4,5可见

volatile应用场景

  • 单例模型双重校验(ps 详情请参看本博主单例模式系列总结文章)

巨人肩膀

zhuanlan.zhihu.com/p/137193948

闲谈

感觉有帮助的同学还请点赞关注,这将对我是很大的鼓励~,公众号有自己开始总结的一系列文章,需要的小伙伴还请关注下个人公众号程序员fly,希望能一起成长。