7.4 最害怕的一集 - volatile
7.4.1 最简单的一集 - volatile 语义 (难度 : ⭐)
读 -> 读一个 volatile 必须从 主内存读
写 -> 写一个 volatile 会把 本地内存 写到 主内存去
7.4.2 最好理解的一集 - volatile 保证了 可见性 ( 难度 : ⭐ )
public class VolatileSTest {
public static void main(String[] args) throws InterruptedException {
Data data = new Data();
new Thread(() -> {
while (true) {
if (data.bool) {
System.out.println("溜了溜了,线程结束了喵!");
break;
}
}
}).start();
TimeUnit.SECONDS.sleep(1);
// 保证新线程后修改
new Thread(() -> {
data.bool = true;
}).start();
}
}
class Data {
// boolean bool = false;
// volatile boolean bool = false;
}
理解方法:
-
如果去掉 volatile : 就会发现 死循环了
-
如果不去掉 volatile : 就会发现 没死循环
自然就很好理解他的 可见性保证
7.4.3 最难复现的一集 - volatile 的 有序性保证 ( 难度 : ⭐⭐⭐⭐ )
为什么给四颗⭐, 因为首先,凭空想想不到,而且真要复现出重排序很难, 个人运行了几千次线程都出不来
class Number {
int i = 1;
volatile int v = 1;
public void set() {
i = 2;
v = 2;
}
public void show() {
if (v == 2) {
System.out.println("t = " + i);
}
}
}
重排序
问题一
两个线程 :
一个调用 show , 一个线程调用 set
重复一遍 !!!! 两个线程: 一个调用 show , 一个线程调用 set
重复一遍 !!!! 两个线程: 一个调用 show , 一个线程调用 set
重复一遍 !!!! 两个线程: 一个调用 show , 一个线程调用 set
因为在单线程中 , 先调用set方法 ,再调用show方法, 因为 happens-before , 是不会允许重排序的
线程一: {
i = 2;
v = 2;
}
线程二: {
if (v == 2) {
System.out.println("t = " + i);
}
}
在不使用 volatile 的情况下
明显,在单线程中 ,两个线程执行的方法体是没有相互依赖的
所以是可以重排序的,所以可以出现
线程一: {
v = 2
i = 2
}
线程二: {
// 先读取 i (即 先准备一下sout)
if(v == 2){
把准备好的i输出
}
}
明显会出现
错误情况一: v = 2 , i = 1 导致 线程二输出 i = 1
错误情况二: v = 2 , i = 2 ,但是!!因为线程二可以准备好 i ,所以线程二输出 i = 1
都是错的
而使用 volatile 就可以避免这些情况
Q: 欸欸欸!凭什么show一定在set之后啊?就不能先show再set吗?
A:
标签:Java,show,关键字,volatile,内存,7.4,线程,public From: https://www.cnblogs.com/deyo/p/17638577.html