从JDK源码看System.exit
来源:互联网 发布:ant maven知乎 编辑:程序博客网 时间:2024/05/01 03:37
前言
在编写的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 JNICALLJava_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() 来退出。
以下是广告和相关阅读
========广告时间========
公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。
鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。
为什么写《Tomcat内核设计剖析》
=========================
相关阅读:
从JDK源码角度看Object
从JDK源码角度看Long
从JDK源码角度看Float
从JDK源码角度看Integer
volatile足以保证数据同步吗
谈谈Java基础数据类型
从JDK源码角度看并发锁的优化
从JDK源码角度看线程的阻塞和唤醒
从JDK源码角度看并发竞争的超时
从JDK源码角度看java并发线程的中断
从JDK源码角度看Java并发的公平性
从JDK源码角度看java并发的原子性如何保证
从JDK源码角度看Byte
从JDK源码角度看Boolean
从JDK源码角度看Short
关注打赏:
- 从JDK源码看System.exit
- 从JDK源码看System.exit
- 从JDK源码看Writer
- 从JDK源码看Writer
- 从JDK源码看InputStream
- 从JDK源码看InputStream
- 从JDK源码看InputStream
- 从JDK源码看OutputStream
- 从JDK源码看Reader
- 从JDK源码看Java并发特性
- 从JDK源码角度看Boolean
- 从JDK源码角度看Object
- 从JDK源码角度看Byte
- 从JDK源码角度看Short
- 从JDK源码角度看Integer
- 从JDK源码角度看Long
- 从JDK源码角度看Long
- 从JDK源码角度看Float
- 用python做词云
- centos 6.8 + pgsql 9.6 + pg_hint_plan
- LINQ体验(6)——LINQ to SQL语句之Join和Order By
- linux文件及路径权限
- “FCoE全解系列”之关键特性和技术分析
- 从JDK源码看System.exit
- Maven error: Failed to execute goal on project : Could not resolve dependencies for project 解决办法
- 在window下安装深度学习环境遇到的坑
- 【第1080期】安息吧 REST API,GraphQL 长存
- LINQ体验(7)——LINQ to SQL语句之Group By/Having和Exists/In/Any/All/Contains
- ASP.NET、.NET和C#的关系是怎样的?
- @keyframes关键帧动画(animation)
- LINQ体验(8)——LINQ to SQL语句之Union All/Union/Intersect和Top/Bottom和Paging和SqlMethods
- 千里之行,始于总结