书上讲的不是很清楚,只说是编译器优化。不是很懂,再怎么优化ready=true不还得执行吗,怎么while(!ready)就退不出来了呢?
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready);
System.out.println(number);
}
}
public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
Thread.sleep(1000);
number = 42;
ready = true;
Thread.sleep(10000);
}
}
这个是一个比较典型的多线程可见性问题。
问题分析
你的
main
方法开启了一个主线程,我们暂且称其为线程AReaderThread.run()
方法开启了线程B,我暂且称其为线程B当线程A运行到
new ReaderThread().start();
方法时,线程B会创建。线程B在竞争拿到CPU资源(一个核心)以后,CPU会将线程B所需要的数据(
ready
)放到CPU缓存中,此时线程B由于是一个死循环,所以线程B会占用一整个核心,如果你这个时候查看CPU使用情况,会发现有一个核心一直都是100%。线程A在运行完
Thread.sleep(1000);
以后,会去修改ready
的值,但这并不会告知线程B,线程B中的ready
也不会被更新,仍然是最开始的初始值。解决方案
java提供了
volatile
关键字,也就是 @听风逝夜 提到的。volatile
用以处理多线程之间数据可见性问题,加了volatile
关键字的变量,CPU在运算时,会直接从主存(我们常说的内存或内存条)读取。这时,当线程A修改ready
的值以后,会将ready
的值刷新到主存中,线程B就对这个被修改的ready
可见了。问题扩展
volatile
除了解决可见性以外,还有其他作用,关于更多volatile
的讲解,可以查看https://www.baeldung.com/java...但需要注意的是,
volatile
只适合读多写少的使用场景,请勿滥用。