import java.util.concurrent.TimeUnit;
/**
* @author gl65293
*
*/
public class StopThread {
/**
* @param args
*/
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable(){
public void run(){
int i = 0;
while(!stopRequested){
i++;
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
在Effective Java 中文版 第二版的230页,说的是这个程序不会停下来. 可你把这个程序放入到eclipse这种ide里去执行的时候,你却发现在很多时候,这个程序都会在执行1秒后停下来. 为什么呢? 这个怎么跟书上说的不一样?
其实, 书上跟自己的实践都是对的, 在eclipse ide里执行这个程序里, 你要加上 -server参数, 这个程序运行就不会停下来了.
这是为什么呢?
因为在加上 -server参数后, jvm会对执行顺序进行优化.
解释如下:
backgroundThread什么时候退出循环是不能确定的,有可能1秒后就退出了,也有可能永远不会退出。程序执行时有如下2中可能情况:
第一种可能,由于stopRequested没有同步或者volatile修饰,jvm为了加快线程的执行速度,每个线程都会对stopRequested做变量拷贝,这时候对变量的修改可能就不会或者不能够及时同步到每个线程中,这种情况backgroundThread 线程什么时候执行结束是不能确定的,>=1秒后结束,或者永远不会结束都有可能。
第二种可能,jvm会对
while(!stopRequested){
i++;
}
做优化,优化后程序执行流程变为
if(!stopRequested) {
while(true){
i++;
}
}
,这种情况,backgroundThread线程永远不会结束。
为了避免以上两种情况,可以用volatile修饰stopRequested,这样每个线程在修改stopRequested后都会把修改结果同步到主内存,每个线程在读取stopRequested时都会从主内存中获取;volatile同时也阻止了jvm对第二种情况的优化
建议细看: 《java并发编程实践》
注:
[color=red]在不加 volatile修饰, 把i++改成System.out.println("t"); 的情况下, 使用-server, -client参数都会在1秒后退出. [/color]
在windows下,jvm默认是client模式, 在linux下默认是 server模式.
参考:
[url=http://www.iteye.com/topic/875420]Java线程安全兼谈DCL[/url]
[url=http://www.iteye.com/topic/260515]用happen-before规则重新审视DCL[/url]