[讨论] System.exit(0) 退出进程的疑惑

gogole_09 2012-02-02
各位大大,请教一下关于System.exit(0)的一个问题,
  具体的代码如下;
 public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(3000);
                        System.out.println("shutdown");
                        System.exit(0);
                    } catch (Exception e) {
                    }
                }
            }
        });
        thread.start();
        
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("hook exit");
                System.exit(0);
            }
        });
        
    }


  这样的话,进程永远无法被关闭掉, 如果去掉 钩子里面显示调用的 System.exit 则可以正常结束掉。
  该问题请各位帮忙分析分析……

补充一下:
JDK 版本:
java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) Server VM (build 19.0-b09, mixed mode)
OS:
Linux i686 i686 i386 GNU/Linux
RednaxelaFX 2012-02-02
问题其实都还没到虚拟机的那层。JDK的文档对此行为描述得很清楚:
http://docs.oracle.com/javase/6/docs/api/java/lang/System.html#exit(int)
引用
The call System.exit(n) is effectively equivalent to the call:

Runtime.getRuntime().exit(n)


http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#exit(int)
引用
If this method is invoked after the virtual machine has begun its shutdown sequence then if shutdown hooks are being run this method will block indefinitely. If shutdown hooks have already been run and on-exit finalization has been enabled then this method halts the virtual machine with the given status code if the status is nonzero; otherwise, it blocks indefinitely.
gogole_09 2012-02-03
多谢R神的解答,  原来API里面就有的。
 
nkhanxh 2012-02-03
我有个问题请教。

那么,为什么行为定义成,如果 正好hooks在运行,就无限等待,然而如果hook完事了,finalize的时候可以异常halt整个vm呢?

为什么不是,如果hooks正在运行,那么会在hook完后取消finalize阶段,直接异常终止呢?

这样不是更加说的过去么?


RednaxelaFX 写道
问题其实都还没到虚拟机的那层。JDK的文档对此行为描述得很清楚:
http://docs.oracle.com/javase/6/docs/api/java/lang/System.html#exit(int)
引用
The call System.exit(n) is effectively equivalent to the call:

Runtime.getRuntime().exit(n)


http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#exit(int)
引用
If this method is invoked after the virtual machine has begun its shutdown sequence then if shutdown hooks are being run this method will block indefinitely. If shutdown hooks have already been run and on-exit finalization has been enabled then this method halts the virtual machine with the given status code if the status is nonzero; otherwise, it blocks indefinitely.

RednaxelaFX 2012-02-03
nkhanxh 写道
我有个问题请教。

那么,为什么行为定义成,如果 正好hooks在运行,就无限等待,然而如果hook完事了,finalize的时候可以异常halt整个vm呢?

为什么不是,如果hooks正在运行,那么会在hook完后取消finalize阶段,直接异常终止呢?

这样不是更加说的过去么?

这恐怕就不是我能回答的问题了…坐等其他人来尝试。
很有可能的原因是当时最初的实现就有这样的特征,于是写在了文档里,后来就变成了“标准行为”。并不是所有规定都一定是深思熟虑后才做出的。
nkhanxh 2012-02-03
嗯。我觉得有可能。

不过我还有个问题,在hooks,和finalize阶段还可以有用户线程运行么?

看样子似乎没说不行?但是似乎很奇怪啊。

我觉得应该一旦开始shutdown hook,就应该挂起所有线程?
RednaxelaFX 写道
nkhanxh 写道
我有个问题请教。

那么,为什么行为定义成,如果 正好hooks在运行,就无限等待,然而如果hook完事了,finalize的时候可以异常halt整个vm呢?

为什么不是,如果hooks正在运行,那么会在hook完后取消finalize阶段,直接异常终止呢?

这样不是更加说的过去么?

这恐怕就不是我能回答的问题了…坐等其他人来尝试。
很有可能的原因是当时最初的实现就有这样的特征,于是写在了文档里,后来就变成了“标准行为”。并不是所有规定都一定是深思熟虑后才做出的。


RednaxelaFX 2012-02-03
nkhanxh 写道
不过我还有个问题,在hooks,和finalize阶段还可以有用户线程运行么?

看样子似乎没说不行?但是似乎很奇怪啊。

我觉得应该一旦开始shutdown hook,就应该挂起所有线程?

当然可以执行。其它线程不受影响。
你可以自己试试用jstack来看。之前有个相关但不相同的例子:http://hllvm.group.iteye.com/group/topic/28230?page=2
nkhanxh 2012-02-03
RednaxelaFX 写道
nkhanxh 写道
不过我还有个问题,在hooks,和finalize阶段还可以有用户线程运行么?

看样子似乎没说不行?但是似乎很奇怪啊。

我觉得应该一旦开始shutdown hook,就应该挂起所有线程?

当然可以执行。其它线程不受影响。
你可以自己试试用jstack来看。之前有个相关但不相同的例子:http://hllvm.group.iteye.com/group/topic/28230?page=2

哦,有意思。
javas 2012-02-06
刚开始我以为是防止递归调用, google 一下

引用
在Hooks里面调用 System.exit(0) 会产生deadlock

http://blog.bielu.com/2009/01/deadlock-while-terminating-jvm.html


然后将上面代码copy run了一下,Jconsole 如下

----- Thread 0 --------
状态:WAITING 在 com.telenav.TestHook$2@1bd7848 上
阻塞总数:0  等待总数: 2

堆栈追踪:
java.lang.Object.wait(Native Method)
java.lang.Thread.join(Thread.java:1258)
java.lang.Thread.join(Thread.java:1332)
java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106)
java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
java.lang.Shutdown.runHooks(Shutdown.java:123)
java.lang.Shutdown.sequence(Shutdown.java:167)
java.lang.Shutdown.exit(Shutdown.java:212)
   - 已锁定 java.lang.Class@14dba7f

----- Thread 1 --------
名称: Thread-1
状态:BLOCKED 在 java.lang.Class@14dba7f 上,拥有者: Thread-0
阻塞总数:1  等待总数: 0

堆栈追踪:
java.lang.Shutdown.exit(Shutdown.java:212)
java.lang.Runtime.exit(Runtime.java:107)
java.lang.System.exit(System.java:960)
com.telenav.TestHook$2.run(TestHook.java:26)

=============================
Thread 0 为应用线程,Thread 1为hook 线程。
Thread 0 使用join 等待Thread 1 线程结束
Thread 1 等待Thread 0 释放 java.lang.Class@14dba7f

形成死锁.

为什么在 on-exit finalization 阶段调用System.exit 不会产生死锁?
I guess 到 on-exit finalization 应用线程已经结束,完全是jvm线程在run。
如何confirm这一猜测,交给各位大神们。

Global site tag (gtag.js) - Google Analytics