//先我们来看看一下下面的代码:
public class Run {
public static void main(String[] args) {
try {
ThreasA threasA = new ThreasA();
threasA.start();
Thread.sleep(1000);
threasA.setRunning(false);
System.out.println("isRuning have already set as false");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
public class ThreasA extends Thread{
private boolean isRunning = true;
public boolean isRunning(){
return isRunning;
}
public void setRunning(boolean isRunning){
this.isRunning = isRunning;
}
@Override
public void run(){
System.out.println("into Run method");
while(isRunning == true){
//此处进行循环
}
System.out.println("The thread have already shutdown");
}
}
大家觉得这个代码会陷入死循环嘛? 每个人去运行的时候,可能也会得到不同的结果。我在自己的eclipse环境下运行时,他的输出是这样子的:
into Run method
isRuning have already set as false
这样子说明,程序是进入了while死循环没有出来,是不是和我们想的有点不一样,因为程序中分明将IsRunning置为false了呀,为什么还会一直执行呢?
其实这样的原因是由于JVM的优化机制导致的,在程序执行时IsRunning= true,存在于公共堆栈以及线程的私有堆栈中,很明显,该变量的值有两份拷贝,在程序运行时,线程一直从自己的私有堆栈中取得isRunning的值,而在代码执行了threasA.setRunning(false);更新的只是公共堆栈中IsRunning的值,而线程私有堆栈中的值变量并没有被更新一直为true。所以就一直陷入死循环。 也就是私有堆栈中的值和公共堆栈中的值同步造成的。
如果在-Server模式运行下也会产生这样的结果,原因基本一样
那么如何解决这一问题呢?那就是使用volatile关键字,使用volatile关键字时,当线程访问IsRunning这个变量时,会强制性从公共堆栈中进行取值。这样就保证了该变量对线程的可见性。关于volatile到底是如何保证变量的可见性的,可以阅读这边博客,讲解的很明白 点击打开链接 还有这篇博客点击打开链接