论坛首页 Java企业应用论坛

Effective Java的一小段代码

浏览 16799 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (5) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-11-24  
TimeUnit.SECONDS.sleep(100);

停0.1秒也不会停止,在client模式下,求解啊
0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间: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变量的副本,而碰到了较长的指令集时就有机会拷贝变量副本了
0 请登录后投票
   发表时间:2011-11-24  
肯定是会停止的啊,多核cpu的,会切换线程的,那么主线程执行了stopRequested = true这个语句,那么子线程  while(!stopRequested)为false退出线程,自然全部结束,注释掉stopRequested = true的话就不会停止了,估计是书印刷的错误。
0 请登录后投票
   发表时间:2011-11-25  
书上说这种优化--提升, 正是HopSpot Server VM的工作。有可能只有Server VM进行了这种优化,Client VM没有对此进行优化。

经试验,运行时加上-server参数时,程序一直在运行,并没有结束。若是没有加上-server参数(Clent VM),程序会在1s左右结束。所以说只有只有Server VM对此进行了优化。

另书中在第2页指明了作者的机器是AMD双核的,所以此处这个问题跟多核好像没多大关系。
0 请登录后投票
   发表时间:2011-11-25  
vamdt 写道
书上说这种优化--提升, 正是HopSpot Server VM的工作。有可能只有Server VM进行了这种优化,Client VM没有对此进行优化。

经试验,运行时加上-server参数时,程序一直在运行,并没有结束。若是没有加上-server参数(Clent VM),程序会在1s左右结束。所以说只有只有Server VM对此进行了优化。

另书中在第2页指明了作者的机器是AMD双核的,所以此处这个问题跟多核好像没多大关系。


试验结果的确如此。

看来,除非设置了明确的同步,在编程中,应该把各个线程的运行看做是高度独立的,互不影响。
即使各个线程轮流获得运行时间片也不例外。

0 请登录后投票
   发表时间:2011-11-25  
前天正好在看《Effective Java》中的多线程部分。跟楼主一样在此处产生了疑惑,看了下面朋友的评论终于豁然开朗。
0 请登录后投票
   发表时间: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);
             }
         });
         
     }

 }
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics