锁定老帖子 主题:Effective Java的一小段代码
精华帖 (0) :: 良好帖 (1) :: 新手帖 (5) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-11-24
TimeUnit.SECONDS.sleep(100);
停0.1秒也不会停止,在client模式下,求解啊 |
|
返回顶楼 | |
发表时间:2011-11-24
nicklasy 写道 Cross_Lee 写道 看书看到这一段代码,书上的意思这个backgroundThread永远不会终止,但是我在机器上跑了下,发现1秒之后程序停止了。我的理解是main线程结束,分出来的子线程都跟着结束。为什么书上说永远不会结束。而且我实验了下是会终止的。有知道的解释下,谢谢各位!
有书的可以看Effective Java 中文版 第二版的230页。 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; } } 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并发编程实践》。 按照书上说的会优化成 if(!stopRequested) { while(true){ i++; } } 按这样的话一旦进入到了while循环那就是死循环了,但是我测试的情况是就算进入了while循环照样会停掉.我机子cpu是双核的,jdk1.6 |
|
返回顶楼 | |
发表时间:2011-11-24
nicklasy 写道 Cross_Lee 写道 看书看到这一段代码,书上的意思这个backgroundThread永远不会终止,但是我在机器上跑了下,发现1秒之后程序停止了。我的理解是main线程结束,分出来的子线程都跟着结束。为什么书上说永远不会结束。而且我实验了下是会终止的。有知道的解释下,谢谢各位!
有书的可以看Effective Java 中文版 第二版的230页。 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; } } 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并发编程实践》。 这位兄台说的应该是对的。如果使用了volatile确实不管多少次都会立马退出了,至于不使用volatile的情况下我尝试把i++换成是System.out.println("test");这样的情况下就跟设置了volatile一样了,这应该是i++的指令一直被执行让CPU没有时间去copy变量的副本,而碰到了较长的指令集时就有机会拷贝变量副本了 |
|
返回顶楼 | |
发表时间:2011-11-24
肯定是会停止的啊,多核cpu的,会切换线程的,那么主线程执行了stopRequested = true这个语句,那么子线程 while(!stopRequested)为false退出线程,自然全部结束,注释掉stopRequested = true的话就不会停止了,估计是书印刷的错误。
|
|
返回顶楼 | |
发表时间:2011-11-25
书上说这种优化--提升, 正是HopSpot Server VM的工作。有可能只有Server VM进行了这种优化,Client VM没有对此进行优化。
经试验,运行时加上-server参数时,程序一直在运行,并没有结束。若是没有加上-server参数(Clent VM),程序会在1s左右结束。所以说只有只有Server VM对此进行了优化。 另书中在第2页指明了作者的机器是AMD双核的,所以此处这个问题跟多核好像没多大关系。 |
|
返回顶楼 | |
发表时间:2011-11-25
vamdt 写道 书上说这种优化--提升, 正是HopSpot Server VM的工作。有可能只有Server VM进行了这种优化,Client VM没有对此进行优化。
经试验,运行时加上-server参数时,程序一直在运行,并没有结束。若是没有加上-server参数(Clent VM),程序会在1s左右结束。所以说只有只有Server VM对此进行了优化。 另书中在第2页指明了作者的机器是AMD双核的,所以此处这个问题跟多核好像没多大关系。 试验结果的确如此。 ![]() 看来,除非设置了明确的同步,在编程中,应该把各个线程的运行看做是高度独立的,互不影响。 即使各个线程轮流获得运行时间片也不例外。 |
|
返回顶楼 | |
发表时间:2011-11-25
前天正好在看《Effective Java》中的多线程部分。跟楼主一样在此处产生了疑惑,看了下面朋友的评论终于豁然开朗。
|
|
返回顶楼 | |
发表时间:2011-11-25
最后修改:2011-11-25
public class StopThread { 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++; } } }); /** * 当java虚拟机中没有非守护线程在运行的时候,java虚拟机会自动关闭。 * Java垃圾回收线程就是一个典型的守护线程 */ backgroundThread.setDaemon(false); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; Runtime.getRuntime().addShutdownHook(new Thread(){ public void run(){ System.out.println("END:" + stopRequested); } }); } } |
|
返回顶楼 | |