staticvoidexit(int status) { booleanrunMoreFinalizers=false; synchronized (lock) { if (status != 0) runFinalizersOnExit = false; switch (state) { case RUNNING: /* Initiate shutdown */ state = HOOKS; break; case HOOKS: /* Stall and halt */ break; case FINALIZERS: if (status != 0) { /* Halt immediately on nonzero status */ halt(status); } else { /* Compatibility with old behavior: * Run more finalizers and then halt */ runMoreFinalizers = runFinalizersOnExit; } break; } } if (runMoreFinalizers) { // 这里是调用 native 方法,不知道为什么调用在 sequence 前 runAllFinalizers(); // 上面和下面调用的是同一个 runAllFinalizers,如果在这里的 halt 导致了退出,则下面的钩子理论上是不会被执行的 halt(status); } synchronized (Shutdown.class) { /* Synchronize on the class object, causing any other thread * that attempts to initiate shutdown to stall indefinitely */ beforeHalt(); // 真正调用的关闭钩子和 finalizer 的地方 sequence(); // 在这里停车 halt(status); } }
/* The actual shutdown sequence is defined here. * * If it weren't for runFinalizersOnExit, this would be simple -- we'd just * run the hooks and then halt. Instead we need to keep track of whether * we're running hooks or finalizers. In the latter case a finalizer could * invoke exit(1) to cause immediate termination, while in the former case * any further invocations of exit(n), for any n, simply stall. Note that * if on-exit finalizers are enabled they're run iff the shutdown is * initiated by an exit(0); they're never run on exit(n) for n != 0 or in * response to SIGINT, SIGTERM, etc. */ privatestaticvoidsequence() { synchronized (lock) { // 这个状态机校验是为了让系统提前返回用的 /* Guard against the possibility of a daemon thread invoking exit * after DestroyJavaVM initiates the shutdown sequence */ if (state != HOOKS) return; } // 运行所有的钩子 runHooks(); boolean rfoe; synchronized (lock) { state = FINALIZERS; rfoe = runFinalizersOnExit; } // 运行所有的 finalizer,这是个 native 方法 if (rfoe) runAllFinalizers(); }
/* Run all registered shutdown hooks */ privatestaticvoidrunHooks() { for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { try { Runnable hook; // 这个锁很重要,目的是通过Happens-Before保证内存的可见性,理论上读写 volatile 变量也可以达到这样的效果,不过这个代码是 java 1.3 时代的产物了 synchronized (lock) { // acquire the lock to make sure the hook registered during // shutdown is visible here. currentRunningHook = i; hook = hooks[i]; } if (hook != null) hook.run(); } catch(Throwable t) { if (t instanceof ThreadDeath) { ThreadDeathtd= (ThreadDeath)t; throw td; } } } }