Java内存模型
JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CPU 指令优化等。JMM 体现在以下几个方面:
- 原子性 - 保证指令不会受到线程上下文切换的影响
- 可见性 - 保证指令不会受 cpu 缓存的影响
- 有序性 - 保证指令不会受 cpu 指令并行优化的影响
代码解读
@Slf4j
public class Test09 {
static boolean flag = true;
public static void main(String[] args) {
new Thread(() -> {
while (flag) {
// 不能执行打印方法,如果使用了不能体现线程不可见,空着就行
}
}, "t1").start();
// 主线程等子线程进入循环后改变flag,但不会影响子线程死循环,因为线程之间存在不可见性(线程有着自己的存储空间,为了性能)
try {
sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("主线程修改标志位");
flag = false;
}
}
结果子线程会死循环
- 解决方法
用volatile修饰flag,子线程的每一次循环就不会从缓存中获取值,而是从主存中获取已经被主线程修改过的值
volatile static boolean flag = true;
volatile(易变关键字)
它可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存
不能保证原子性,仅用在一个写线程,多个读线程的情况,如果多个线程写(i++问题),是不能防止指令交错的,还是会存在线程安全问题。
synchronized区别
synchronized 语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是
synchronized 是属于重量级操作,性能相对更低,synchronized 是不能保证指令重排的,它的有序是保证了多个线程之间的同步有序