有如下一段程序代码:
public class Demo {
private static boolean stop = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
int i=0;
while(!stop){
i++;
}
System.out.println("the thread is stopped.i="+i);
});
thread.start();
Thread.sleep(1000);
stop = true;
}
}
执行后,没有任何输出。线程却不停止。
说明while循环仍在执行,那么stop的值仍为false,说明stop=true
对while并没有生效。
这就是多线程的可见性问题。
就是我们在外层将值改变,子线程没有看到变化。
如果要解决它,可以使用volatile关键字。
public class Demo {
private volatile static boolean stop = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
int i=0;
while(!stop){
i++;
}
System.out.println("the thread is stopped.i="+i);
});
thread.start();
Thread.sleep(1000);
stop = true;
}
}
这次的结果为:
除了使用volatile关键字外,
如果在循环体while
中加入 Thread.sleep(0);
或者 System.out.println("the i="+i);
也可以停止线程。
为什么 Thread.sleep可以停止线程?
加Thread.sleep(0)
可以停止线程的原因是:
这是因为在hotspot的server端虚拟机中,做了深度优化(client版本就没有这个问题)。
C:\Users\86137>java -version
java version "1.8.0_361"
Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)
JIT 做了如下的优化:
while(!stop){
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//-->
if(!stop){
while(true){
i++;
}
}
volatile可以禁止JIT的优化过程。
除了volatile,我们可以通过VM参数来设置JIT禁止优化:
首先我们把代码中private tatic boolean stop = false;
中的volatile去掉;
然后在执行的VM参数中配置-Djava.compiler=NONE
就会发现 while中的stop生效了,线程会停下来。
为什么print可以导致循环结束?
print中包括两个步骤,1.IO操作;2.Synchronized。
Synchronized的释放,会将工作内存中的操作同步到主内存。所以stop最新的值会被while(!stop)读取到。
我们可以从如下示例中看到这个现象:
while(!stop){
i++;
synchronized (Demo.class){
}
}
加了一个Synchronized的锁,会发现线程开启执行后,会停下来。
而IO操作会涉及到与内存、硬盘的交互,它会阻塞线程。 比如:
while(!stop){
i++;
new File("test.java");
}
加了IO操作,也会使线程停下来。