请看以下代码
public class TestVolatile {
public static void main(String[] args) throws InterruptedException {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
Thread.sleep(1);
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
把Thread.sleep(1)
换成Thread.sleep(1000)
就能获取flag
修改后的值,即td.isFlag()
返回true
。
虽然看了Java内存模型的概念,但我不知道如何解释这段代码,谁能解释一下?
相关问题: Java多线程的工作内存是什么?
你得先说说你的预期效果是啥?问问题要问清楚啊
这个期待是没有规范支撑的。代码中没有做任何能保证 "子线程写 happen-before 主线程读" 的事情。
sleep(1000)
后看到修改只是巧合,一个JVM如果在更久后才让主线程看到,甚至永远不让主线程看到都不违反规范。你的程序应该是想测试
volatile
关键字的功能。但是 “把Thread.sleep(1)
换成Thread.sleep(1000)
就能获得预期效果” 这样做理解上是不对的。首先,程序中总共有两个线程,主线程(暂称 线程M)和
new Thread(td)
(暂称 线程T)。当写
Thread.sleep(1)
的时候,线程M 在 1ms 之后,便开始在while(true)
循环中检查td.isFlag()
的值,但是因为内存可见性的关系,线程M 并不能及时读取 线程T 中 flag 的值,所以此时导致了死循环;当写
的值设为Thread.sleep(1000)
的时候,M 在 1000ms 之后,开始在while(true)
循环中检查td.isFlag()
的值;但是 T 在 200ms 的时候,便将Thread.sleep(1000)
的时候,M 在 1000ms 之后,开始在while(true)
循环中检查td.isFlag()
的值;但是 T 在 200ms 的时候,便将 flag 的值设为true
了,所以,M 在 1000ms 之后检测td.isFlag()
的值肯定是返回true
的,那么第一次判断便会返回true
,产生输出并跳出while(true)
flagtrue
了,所以,M 在 1000ms 之后检测td.isFlag()
的值肯定是返回true
的,那么第一次判断便会返回true
,产生输出并跳出while(true)
循环。为了让 线程M 及时读取到 线程T 中 flag 的值,需要将 flag
关键字进行修饰:volatile
使用volatile
的修改,其他线程都立马可见。关于 的使用,可以参考我的博客:Java 多线程(6):volatile 关键字的使用🎜可以参考如下三个代码:
其中第一个和你的情况一样,由于多线程的可见性问题,可能导致无限循环下去。
第二个是使用
synchronized
解决此问题,大多数工作场景用这个好synchronized
解决此问题,大多数工作场景用这个好第三个是使用
volatile
第三个是使用volatile
解决,但这个关键字只保证可见性,在实际场景中局限性比较大,得慎用