代码如下,首先生成一个线程数组,如果数组小(3-5个),看起来执行正常,shutdownhook中定义的线程会在最后执行,但一旦线程数组加大,如100,200,则shutdownhook中定义的线程会在虚拟机没有退出前的最后一步执行,会在中间的某个时间点启动该线程。请大家讨论一下原因,以及Runtime.getRuntime().addShutdownHook()的执行机理,是否和JDK文档中说的会在jvm退出前执行。我的测试环境是Ubuntu 8.04, jdk1.5.0_17,jdk1.6.0_11
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/**
 *
 * @author qi
 */
public class SyncLockDemo2 {    public static void main(String[] xxx) {
        Thread[] threads = new Thread[100];
        final long t = System.nanoTime();
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run(){
                System.err.println((System.nanoTime()-t)/1000000);
            }
        });
        final byte[] lock1 = new byte[0];
        final Lock lock2 = new ReentrantLock();
        for (int i = 0; i < threads.length; i++) {
            final int index = i;
            Runnable run = new Runnable() {                public void run() {
                    synchronized (lock1) {
                        for (int k = 0; k < 1000; k++) {
                            System.out.println(index + ":" + k);
                        }
                    }
                }
            };
            threads[i] = new Thread(run);
        }
//        for (int i = 0;
//                i < threads.length;
//                i++) {
//            final int index = i;
//            Runnable run = new Runnable() {
//
//                public void run() {
//                    try {
//                        lock2.lock();
//                        for (int k = 0; k < 1000; k++) {
//                            System.out.println(index + ":" + k);
//                        }
//                    } finally {
//                        lock2.unlock();
//                    }
//                }
//            };
//            threads[i] = new Thread(run);
////            threads[i].setDaemon(true);
//        }
        for (int i = 0;
                i < threads.length;
                i++) {
            threads[i].start();
        }    }
}

解决方案 »

  1.   

    那是因为你的程序写的不对,在hook里应该用System.out来输出
    比如System.out.println("***"+(System.nanoTime()-t)/1000000);
    这样不管你用多少个线程,hook都会在最后输出。
    因为out和err是不同的流,线程少的时候结果正确仅仅是err缓冲在最后刷新的几率比较大而已。
      

  2.   

    err是我故意写的,就是为了测试不同管道处理的效果。
    是否我可以这样理解:多个线程在处理系统管道的事情的时候,shutdownhook是可以判断的还是无法判断的?
      

  3.   

    晕,写的语无伦次了,CSDN还不允许修改。
    /************************/
    是否我可以这样理解:多个线程在处理系统管道的事情的时候,shutdownhook是无法判断的?
      

  4.   

    我觉得shutdownhook是可以判断的。
    至于为什么会出现hook没有打印在最后,是因为不同的管道刷新时间的不确定造成的。
      

  5.   

    可以这样理解。shutdown hook仅仅是一个简单的被初始化但还没被启动的线程。当虚拟机启动关闭流程时,会启动所有注册了的shutdown hook,并且以只用不确定的次序执行这些shutdown hook线程。当所有shutdown hook线程都结束时,如果finalization-on-exit被设置为可用,虚拟机会执行所有为唤醒的finalizer。最后,虚拟机会被挂起。
      

  6.   

    我觉得这是输出管道缓存的问题
    jvm退出时才执行hook,这点应该是没问题的
    线程是通过out管道输出的,由于数量大时out管道不能及时处理过来,把数据都保存在缓存里
    当所有的线程执行完后退出jvm,此时hook被调用,由于err只有少量数据,立刻被打印出来
      

  7.   


    应该是无法判断的,管道输出是系统级别控制的(输出设备由系统管理),shutdownhook是jvm控制的,jvm的线程只管把数据传给管道,并不能保证管道一定要输出结束,如果非要控制,那就使用输出重定向,然后判断所有的数据都输出结束后再退出jvm