Volatile介绍
volatile是JAVA虚拟机提供的轻量级的同步机制
volatile字面意思是易变的、不稳定的。
volatile是一个类型修饰符,使用方式如:
static volatile int i=0;
Volatile作用
1.线程的可见性:当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
2. 顺序一致性:禁止指令重排序。
volatile可见性
volatile关键字的作用是保证变量在多线程之间的可见性,它是java.util.concurrent包的核心
内存屏障(memory barrier),这是一条CPU指令,可以影响数据的可见性。当变量用volatile修饰时,
将会在写操作的后面加一条屏障指令,在读操作的前面加一条屏障指令。
这样的话,一旦你写入完成,可以保证其他线程读到最新值,也就保证了可见性
volatile不保证原子性
原子性是说一个操作是不可中断的,不可分割的。
volatile不能保证完全的原子性,只能保证单次的读/写操作具有原子性。
对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量,
但是并不能保证i++这种操作的原子性,因为本质上i++是读、加一、写三次操作,
volatile并不能保证这三次操作的原子性。
volatile禁止指令重排序
指令重排序是指JAVA语言规定JVM线程内部维持顺序化语义(满足
As-If-Serial语义和Happens-Before原则),即只要程序执
行的最终结果与其顺序化执行的结果相同,JVM允许指令执行的顺
序与代码逻辑书写的顺序可以不一致,这样的过程叫做指令重排序。
指令重排序的意义是指令更加符合CPU执行的特性,提高执行效率
但是在多线程中某些时候指令重排序会让程序出现预期之外的结
果(如DCL中会造成线程不安全),所以我们有时候需要禁止JVM做
这种指令重排序的优化。
volatile通过加入内存屏障防止这种指令重排,用volatile修
饰的变量在写操作时在volatile写的前后分别加入StoreStore
屏障和StoreLoad屏障防止写操作时发生指令重排,在volatile
读操作之后加入LoadLoad屏障和LoadStore屏障防止读操作时
发生指令重排序
Volatile与Synchronized比较
原子性问题解决 使用 synchronized 关键字
Volatile是轻量级的synchronized,因为它不会引起上下文的切换和调度,所以Volatile性能更好。
Volatile只能修饰变量,synchronized可以修饰方法,静态方法,代码块。
Volatile对任意单个变量的读/写具有原子性,但是类似于i++这种复合操作不具有原子性。而锁的互斥执行的特性可以确保对整个临界区代码执行具有原子性。
多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。
volatile是变量在多线程之间的可见性,synchronize是多线程之间访问资源的同步性