2018-08-05
volatile基础
[TOC]
1.概念
A.轻量级同步机制,与synchronized重量级锁不同,不会引起线程的上下文切换,但是需要注意两个问题:
- 复合类操作无法同步 如 count++
- 在其他变量的不变式中包含则无法同步 如常量和条件(后续再深入理解不变式)
B.阻止指令重排
2.内存可见性
volatile是轻量级的同步机制,相比于synchronized重量级锁来说 ,能够节省更大的消耗,虽然在总体能力上不如synchronized安全,但是在一定场合也具有自己的优势,合理的利用volatile能够让程序更高效的运行
volatile修饰的属性对整个内存来说是可见的,即:每个线程获取到的该数据都是最新的(此处内存分配属逻辑模拟)
- A线程(工作内存)→
} 主内存空间
- B线程(工作内存)→
对线程来说,正常的共享资源会从主内存中copy到自己的工作内存中,这里如同内存和硬盘的区别,可以更加快速的使用copy的资源,但是此时的工作内存对于其他线程是不可见的,因此很容易因为并发产生数据异常
当使用volatile时,该共享资源每次更新都会被同步到主内存空间中,对于其他线程来说,该数据始终是最新的,因此可以一定程度的解决并发的问题,但是有一些情况volatile无法直接实现,如非复合类操作
3.解决count++原子性问题
count++之类的非符合类操作,volatile无法保证他的原子性问题,使共享资源无法实时同步,进而引发并发问题
复合类操作过程:
- 读取
- 运算
- 赋值
因为volatile本身只是轻量级的同步机制,并非锁机制,当复合类操作的过程中可能有其他线程继续操作该资源,从而导致并发问题
解决:循环CAS 方案(待研究)
4.阻止指令重排
指令重排是java优化程序性能的一种手段(提供并行度),但是重排也有一定的规则:
指令重排不会对存在依赖关系的数据进行操作
如a=1;b=a
指令重排不会对单线程下的结果进行操作
如a=1;b=2;c=a+b;
被volatile修饰的变量,在编译时,会插入内存屏障来阻止处理器等对数据的指令重排,阻止指令重排规则:
- 第一个是volatile读操作时,无论第二个是什么操作,都会阻止指令重排
- 第二个是volatile写操作时,无论第一个是什么操作,都会阻止指令重排
- 第一个是volatile写操作,得个是volatile读操作时,都会阻止指令重排