多线程——JMM多线程共享变量的不可见性
多线程——JMM多线程共享变量的不可见性
示例1:
public class Demo1 {
private static boolean flag = false;
public static void main(String[] args) {
// 线程1 读flag的值
new Thread(() -> {
while (true) {
if (flag) {
System.out.println("线程1 读 flag=" + flag);
System.exit(0);
}
}
}).start();
// 注释1:等一会线程1,至少把主内存中flag的值复制到自身的工作内存
// try {
// Thread.sleep(1);// 等待时间大一点,线程1的工作内存即可初始化完成
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// 线程2 写flag的值
new Thread(() -> {
while (true) {
flag = true;
}
}).start();
}
}
不打开注释1,结果
- 线程1 读 flag=true
打开注释1,结果有两种
- 1.打印main sleep 之后陷入死循环
- 2.打印main sleep 线程1 读 flag=true
打开注释1的第二种结果比较少见,这是因为线程1还没把主内存中的flag复制到工作内存中。
根据JMM模型,显然在打开注释1出现的第一种结果是符合预期的。线程1从主内存复制了最初的一份flag=false到自己的工作内存中,之后主内存中的flag=true,并没有更新到线程1的工作内存。因此线程1看到的flag一直是最初的false。
示例2:
public class Demo2 {
private static boolean flag = true;
public static void main(String[] args) {
new Thread(()->{
while (flag){
// 注释1:
// System.out.println("over");
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag=false;
}
}
不打开注释1,结果
- 陷入死循环
打开注释1,结果
- 输入多次 over 然后正常退出
不打开注释1的结果是符合预期的,线程1的工作内存中的flag一直是最初从主内存拷贝的值true,所以陷入死循环。
打开注释1的结果,预想是一直循环输入over,但是程序会在输出一定次数后正常退出。这是为什么呢?这是由于 打印语句触发了happens-before操作。
JMM多线程共享变量的不可见性该如何解决呢?一、加锁,二、部分场景下可以使用volatile关键字。
参考:

浙公网安备 33010602011771号