从JDK源码看System

撸了今年阿里、腾讯和美团的面试,我有一个重要发现…….

作者:超人汪小建(seaboat)

出处:https://blog.csdn.net/wangyangzhizhou/column/info/16032


前言

在编写的Java程序中有时会遇到用 System.exit 来关闭JVM,其中调用 exit 方法时会包含一个状态参数n,即System.exit(n)。这其实是一个约定值,如果为0则表示正常关闭,而非0则表示非正常关闭。这里我们从JDK源码看下不同状态都是怎么处理的。

System与Runtime

先看System类的exit方法如下,可以看到它是间接调用了Runtime对象的exit方法。

    public static void exit(int status) {
        Runtime.getRuntime().exit(status);
    }

而Runtime的exit方法如下,先使用SecurityManager检查是否有关闭JVM的权限,允许执行则调用Shutdown的exit方法。

    public void exit(int status) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkExit(status);
        }
        Shutdown.exit(status);
    }

Shutdown

进入到Shutdown类的exit方法,Java层面还有自己的状态state,它可能值为RUNNING、HOOKS和FINALIZERS,可以看到里面的主要逻辑是:
1. 不管什么状态下,status为非0时不执行任何Finalizer。
2. 在RUNNING状态下,状态转成HOOKS,然后先执行sequence方法,再执行halt方法停止JVM。
3. 在FINALIZERS状态下,status为非0时直接 就调用halt方法停止JVM了,而status为0时还需要执行所有的finalizer,之后才调用halt方法停止JVM。

        static void exit(int status) {
            boolean runMoreFinalizers = false;
            synchronized (lock) {
                if (status != 0) runFinalizersOnExit = false;
                switch (state) {
                case RUNNING:       
                    state = HOOKS;
                    break;
                case HOOKS:         
                    break;
                case FINALIZERS:
                    if (status != 0) {
                        halt(status);
                    } else {
                        runMoreFinalizers = runFinalizersOnExit;
                    }
                    break;
                }
            }
            if (runMoreFinalizers) {
                runAllFinalizers();
                halt(status);
            }
            synchronized (Shutdown.class) {
                sequence();
                halt(status);
            }
        }

sequence方法主要是控制钩子和Finalizer执行的顺序,判断状态不为HOOKS则直接返回,然后执行所有的钩子,把state改为FINALIZERS,最后执行所有finalizer。

    private static void sequence() {
            synchronized (lock) {
                if (state != HOOKS) return;
            }
            runHooks();
            boolean rfoe;
            synchronized (lock) {
                state = FINALIZERS;
                rfoe = runFinalizersOnExit;
            }
            if (rfoe) runAllFinalizers();
        }

halt方法

执行JVM是通过halt方法实现,这时System.exit(n)的状态n继续往下传递,最终是调用了一个本地的halt0方法。

    static void halt(int status) {
        synchronized (haltLock) {
            halt0(status);
        }
    }

    static native void halt0(int status);

对应的本地方法如下,主要是调用了JVM_Halt函数,

    JNIEXPORT void JNICALL
    Java_java_lang_Shutdown_halt0(JNIEnv *env, jclass ignored, jint code)
    {
        JVM_Halt(code);
    }

继续往下,JVM_Halt函数主要包含了before_exit函数和vm_exit函数,before_exit函数主要做退出前的一些工作,它只会被执行一次,在多个线程情况下只有获取锁的才能执行,其他线程都必须等。

    JVM_ENTRY_NO_ENV(void, JVM_Halt(jint code))
      before_exit(thread);
      vm_exit(code);
    JVM_END

而vm_exit函数如下,这里code仍然是Java调用System.exit(n)时传递来的,最主要的是vm_direct_exit函数,它先向jvm发出关闭通知,然后再调用exit函数退出,状态值继续往下传,这时的状态值已经传递到操作系统的API。

    void vm_exit(int code) {
      Thread* thread = ThreadLocalStorage::is_initialized() ?
        ThreadLocalStorage::get_thread_slow() : NULL;
      if (thread == NULL) {
        vm_direct_exit(code);
      }

      if (VMThread::vm_thread() != NULL) {
        VM_Exit op(code);
        if (thread->is_Java_thread())
          ((JavaThread*)thread)->set_thread_state(_thread_in_vm);
        VMThread::execute(&op); VM Thread.
        vm_direct_exit(code);
      } else {
        vm_direct_exit(code);
      }
      ShouldNotReachHere();
    }
    void vm_direct_exit(int code) {
      notify_vm_shutdown();
      os::wait_for_keypress_at_exit();
      ::exit(code);
    }

总结

Java的System.exit(n)的状态码最终是传递到操作系统的API,所以它的含义与操作系统API的含义相关,当然这个过程Java还会有自己的一些机制工作需要处理。可以说目前大多数平台都可以在 main 函数中直接 return退出程序,但某些平台下不能这样处理,所以为了兼容需要使用 exit() 来退出。

赞(1) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » 从JDK源码看System
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注【Java 技术驿站】公众号,每天早上 8:10 为你推送一篇技术文章

扫描二维码关注我!


关注【Java 技术驿站】公众号 回复 “VIP”,获取 VIP 地址永久关闭弹出窗口

免费获取资源

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏