Voltatile关键字
1.Voltatile是一个轻量级锁,相比重量级锁synchronized,只保证可见性,不保证原子性。
2.Voltatile时修饰共享变量的,synchronized时用来修饰变量的调用者。
-
内存模型的相关概念
共享变量:所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享,说简单点,就是全局变量,静态变量,以及数组,对象等,在多线程中可以称之为共享变量。
缓存不一致:一个变量在多个CPU中缓存时,当各CPU从高速缓存中更新数据到主存时。缓存不一致的解决方案:
1)通过在总线加LOCK#锁的方式(一个线程访问时上锁,其他线程访问不了,效率低)。
2)通过缓存一致 -
并发编程的三大特性
1.可见性
只要有一个线程将变量的值改了,马上就会同步到内存,其他的线程马上就可以得到这个改过后的值。
2.原子性
我们把一个或者多个操作在CPU执行的过程中不被中断的特性称为原子性,要么同时成功,要么同时失败。但是volatile不保证原子性。
3.有序性
有序性指的是程序按照代码的先后顺序执行 -
Java的内存模型(Java Memory Model简称JMM)
1.JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是属于JVM的。
2.java内存模型中规定所有的变量都存储在主内存,主内存是所有线程都可以访问的空间。但是线程对变量的操作(读取和赋值)都是在自己的工作空间内完成,首先要将变量拷贝到自己的工作空间,然后对变量进行操作,操作完成再将变量写回到主内存。 -
Voltatile关键字的原理和实现机制
1.Voltatile的特点:
1)保证内存可见性
2)不保证原子性
3)禁止指令重排(保证有序性)
2.代码加入Voltatile关键字之后,会多出一个lock的前缀指令,相当于一个内存屏障(即解决缓存不一致)
lock前缀指令:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面(即在执行到内存屏障这句指令时,在它前面的操作已经全部完成),从而禁止指令重排序
(1)单线程环境, 重排序能保证程序的最终结果和顺序执行的结果一致
(2)多线程调度过程中, 由于重排序存在, 两个线程的变量无法保证一致性
volatile实现了禁止指令重排的优化,从而避免了多线程环境下出现程序乱序执行的现象。2)它会强制将对缓存的修改操作立即写入主存,以保证内存可见性
public class TestVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("----");
break;
}
}
}
}
class ThreadDemo implements Runnable {
// 给变量加上volatile关键字,实现内存可见性
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
当主存中的值改变的时候,可以及时通知其他线程,保证每次能够更新到最新数据
- 使用Voltatile关键字的场景
synchronized 关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率;而 volatile 关键字在某些情况下性能要优于 synchronized,但是要注意 volatile 关键字是无法替代 synchronized 关键字的,因为 volatile 关键字无法保证操作的原子性。通常来说,使用 volatile 必须具备以下两个条件: 1)对变量的写操作不依赖于当前值;
2)该变量没有包含在具有其他变量的不变式中。
关键字Voltatile主要适用的场景是:
1.状态标记量
// 示例 1
volatile boolean flag = false;
while(!flag){
doSomething();
}
public void setFlag() {
flag = true;
}
用于判断满足某个条件时执行某个事件
// 示例 2
volatile boolean inited = false;
//线程1:
context = loadContext();
inited = true;
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
2.double-check(双重检查)
在使用之前检查数据是否使用过
class Singleton{
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}