什么是内存可见性
一个线程对主内存中的数据修改了,但是其他线程不可见。造成了内存可见性问题。
主内存是什么
工作内存是什么
存储私有变量
// 永不终止的循环 - 可见性问题public class TestInfinityLoop {static boolean stop = false; //停止标记public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}stop = true; // volatile 的写System.out.println("t线程内存:" + stop);});System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));System.out.println("主线程内存:" + stop);t.start();//Thread t2 = new Thread(() -> {// try {// Thread.sleep(1000);// } catch (InterruptedException e) {// e.printStackTrace();// }// stop = true; // volatile 的写// System.out.println("t2线程内存:" + stop);//});//t2.start();//System.out.println("主线程内存:" + stop);foo();}private static void foo() {while (true) {boolean b = stop; // volatile 的读if (b) {break;}}System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}}
start 17:30:32 主线程内存:false t线程内存:true
这个代码和视频里讲的,启动两个线程,其中stop会将主内存中值修改为TRUE,实际上,一个线程的线程结果都是将主内存中的值改为TRUE。和多线程无关。
我们来看看两个线程的结果打印
// 永不终止的循环 - 可见性问题public class TestInfinityLoop {static boolean stop = false; //停止标记public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}stop = true; // volatile 的写System.out.println("t线程内存:" + stop);});System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));System.out.println("主线程内存:" + stop);t.start();Thread t2 = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}stop = true; // volatile 的写System.out.println("t2线程内存:" + stop);});t2.start();System.out.println("主线程内存:" + stop);foo();}private static void foo() {while (true) {boolean b = stop; // volatile 的读if (b) {break;}}System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}}
最终输出都是
start 17:30:12 主线程内存:false 主线程内存:false t2线程内存:true t线程内存:true
初始状态, t 线程刚开始从主内存读取了 run 的值到工作内存

再尝试用 -Xint 强制解释执行
禁用JIT编译器优化命令
上面的结果start 18:10:44主线程内存:falset线程内存:trueend 18:10:45
再用 -XX:+PrintCompilation 看看实时编译后的代码

这个就代表着编译被优化了。解决方案
加上volatile(易变)的关键字
public class TestInfinityLoop {volatile static boolean stop = false; //停止标记public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}stop = true; // volatile 的写System.out.println("t线程内存:" + stop);});System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));System.out.println("主线程内存:" + stop);t.start();foo();}private static void foo() {while (true) {boolean b = stop; // volatile 的读if (b) {break;}}System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}}
或者用synchronized解决
public class TestInfinityLoop {static boolean stop = false; //停止标记private static final Object lock = new Object();public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock) {stop = true; // volatile 的写}System.out.println("t线程内存:" + stop);});System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));System.out.println("主线程内存:" + stop);t.start();foo();}private static void foo() {while (true) {synchronized (lock) {boolean b = stop; // volatile 的读if (b) {break;}}}System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));}}
总结
synchronized可以解决可见性、原子性、有序性,但是它是重型锁。而volatile能解决可见性和有序性,但不能解决原子性。
