JAVA并发之volatile关键字

简介

volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,相对于synchronized,它只保证了变量可见性,没办法保证并发的正确性。Java内存模型对volatile专门定义了一些特殊的访问规则。它有两种特性,1.所有线程的可见性 2.禁止指令重排序优化。先记住这两个特性,首先说明下Java内存模型---JMM。

JMM

Java虚拟机规范定义了一种Java内存模型---JMM来屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。Java虚拟机规范定义了如下所示的JMM模型,其中工作内存是线程独有的,它会存储线程在运行过程中所用到的变量的主内存拷贝!(和基于高速缓存的存储交互式模型相似的)

JAVA并发之volatile关键字_第1张图片

 

 

主内存和工作内存之间的交互有具体的交互协议,JMM定义了八种操作来完成,这八种操作是原子的、不可再分的,它们分别是:lock,unlock,read,load,use,assign,store,write(具体作用请参考Java内存模型八个操作)。

接下来从顶到下的来介绍下volatile的工作原理。

volatile禁止指令重排序

首先对于定义的一个volatile变量,赋值后汇编代码会多执行一个"lock addl $0x0, (%exp)"操作,这个操作很关键

1、这个操作相当于一个内存屏障(指令重排序时不可以把后面的指令重排序到内存屏障之前的位置),在多CPU访问一个内存时候,并且其中有一个正在观测另外一个,这时候内存屏障就可以来保证内存一致性。注:指令重排序是指CPU采用了允许将多条指令不按照程序规定的顺序分开发送给各相应电路单元处理,但并不是说指令任意重排,CPU需要能正确处理指令依赖情况以保证程序能得出正确的执行结果。

2、这个操作中的add $0x0,(%esp)是一个空操作,关键在于lock前缀的作用是使得本CPU的cache写入了内存,这个写入动作也会引起别的CPU或内存无效化其cache。所以这个操作可以让前面对volatile变量的修改对其他CPU立即可见。

volatile可见性

Java内存模型对volatile变量定义了特殊的规则来保证可见性

1、只有当线程对V变量执行的前一个动作是load时候,线程才可以对V变量执行use动作,反之也必须满足

2、只有当线程对V变量执行的前一个动作是assign时候,线程才可以对V变量执行store动作,反之也必须满足

这两个规则保证了volatil变量的读取和写入都是相当于直接从主内存进行的,从而确保了可见性!

volatile变量性能

volatile变量的读操作的性能消耗几乎与普通变量没什么区别,但是写操作要慢一些,因为它需要在本地代码中插入许多的内存屏障来保障处理器不发生乱序执行。但总之,它与锁比较起来总开销仍较低。

volatile变量的HB规则

对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”是指时间上的先后顺序。

你可能感兴趣的:(JAVA并发之volatile关键字)