谈谈对 Volatile 的了解
- volatile 是 JVM 提供的轻量级的同步机制
volatile 有三大个性
- 保障可见性
- 不保障原子性
- 禁止指令重排
JMM 是什么
- JMM(Java 内存模型,简称 JMM)自身是一种形象的概念并不实在存在
- 因为 JVM 运行程序的实体是 线程 ,而每个线程创立时 JVM 都会为其创立一个工作内存, 工作内存是每个线程的公有数据区域 ,而 Java 内存模型中规定所有变量都存储到主内存, 主内存是共享内存区域,所有线程都能够拜访,但线程对变量的操作必须在工作内存中进行。
- 首先要将变量从主内存 拷贝 到本人的工作内存空间,而后对变量进行操作,操作实现后再将变量写回主内存,不能间接操作主内存中的变量,因而不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来实现。
数据传输速率:硬盘 < 内存 < < cache < CPU
下面提到的概念 主内存 和 工作内存:
- 主内存:次要包含 本地办法区 和堆
- 工作内存:属于该线程 公有的栈 和对主存局部变量拷贝的 寄存器(包含程序计数器 PC 和 cup 工作的高速缓存区)
JMM 的个性
JMM 的三大个性:可见性,原子性,有序性
volatile 只保障了两个,即可见性和有序性,不满足原子性
可见性(及时告诉)
- 指的是当主内存区域中的值被某个线程写入更改后,其它线程会马上通晓更改后的值,并重新得到更改后的值。
- 例如:有三个线程往主线程批改变量 age=20,三个线程各自变量拷贝一份,其中一个线程在本人的工作空间将 20 改成了 25,而后将工作内存中的值,写入主内存,主内存中的值被批改后,其余工作内存中的值会马上取得告诉。
用 volatile 验证可见性
咱们对于成员变量没有增加任何润饰时,是无奈感知其它线程批改后的值
class MyData {
// 定义 int 变量
int number = 0;
// 增加办法把变量 批改为 60
public void addTo60() {this.number = 60;}
}
public class Test {public static void main(String[] args) {
// 资源类
MyData myData = new MyData();
// 用 lambda 表达式创立线程
new Thread(() -> {System.out.println("线程进来了");
// 线程睡眠三秒,假如在进行运算
try {Thread.sleep(3000);
} catch (InterruptedException e) {e.printStackTrace();
}
// 批改 number 的值
myData.addTo60();
// 输入批改后的值
System.out.println("线程更新了 number 的值为" + myData.number);
}).start();
// main 线程就始终在这里期待循环,直到 number 的值不等于零
while (myData.number == 0) { }
System.out.println("main 办法完结了");
}
}
最初线程没有进行,没有输入 main 办法完结了 这句话,阐明没有用 volatile 润饰的变量,是没有可见性的。
当咱们给变量增加 volatile 关键字润饰:volatile int number = 0
,发现能够胜利输入完结语句。
⭐volatile 润饰的关键字,是为了减少 主线程和线程之间的可见性,只有有一个线程批改了内存中的值,其它线程也能马上感知,是具备 JVM 轻量级同步机制的。