简单介绍
Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
可见性
如果线程t1与线程t2分别被安排在了不同的处理器上面,那么t1与t2对于变量A的修改时相互不可见,如果t1给A赋值,然后t2又赋新值,那么t2的操作就将t1的操作覆盖掉了,这样会产生不可预料的结果。
i++是原子操作吗
对于基本类型来说,读取与赋值是安全的原子性操作(long除外)
不是,i++(读改写)操作涉及到以下三个步骤
- 内存到寄存器
- 寄存器自增
- 写回到内存
这三个阶段中间都可以被中断分离开
实现原理
有volatile变量修饰的共享变量进行写操作的时候会多出第二行汇编Lock前缀,Lock前缀的指令做了两件事情
- 将当前处理器缓存行的数据写到系统内存。
- 这个写会内存的操作会使其他cpu里缓存了该内存地址的数据无效
Lock前缀锁缓存锁定,例如当cpu1 对某个缓存行进行了缓存锁定,在它通过锁机制回写到内存时,这时会因缓存一致性会阻止同时修改被多个处理器缓存的内存数据;当cpu1回写到内存成功时,会使其他cpu的缓存数据无效。
处理器实现原子操作
- 总线锁:当cpu1在读改写共享变量时,其他cpu不能操作缓存了该变量内存地址的缓存(锁cpu到内存的通信)
- 缓存锁:cpu1回写到内存成功时,会使其他cpu的缓存数据无效。
JAVA如何实现原子操作
在java中可以通过锁和循环CAS的方式来实现原子操作。
volatile有可见性,非原子性
volatile提供轻量级同步机制
因为volatile声明的变量是直接在主内存中直接对数据进行操作,所以可以保证在多线程情况下变量的一致性。
Java的内存分主内存和线程工作内存,volatile保证修改立即由当前线程工作内存同步到主内存,但其他线程仍需要从主内存取才能保证线程同步。
什么是重排列
除了可见性,还有禁止指令重排
我们可以确定volatile的读操作性能与普通变量没啥区别,写操作要慢些,因为它要在本地代码中插入许多内存屏障来保证处理器不发生乱序执行。
什么情况下用volatile
可以用volatile的地方:对一个变量,更新其值的时候不依赖于当前值,且该变量不会和其他一起构成一个不可变条件。
该变量不会和其他一起构成一个不可变条件
有范围值 lower总是小于等于upper 这是一个不变式
public class NumberRange{
private volatile int lower ,upper ;
public int getLower(){
return lower ;
}
public int getUpper(){
return upper ;
}
public void setLower( int value){
if (value > upper) throw new IllegalArgumentException( ...);
lower = value;
}
public void setUpper( int value){
if (value < lower) throw new IllegalArgumentException( ...);
upper = value;
}
}
volatile使用案例

网友评论