在編寫的Java程序中有時會遇到用 System.exit 來關閉JVM,其中調用 exit 方法時會包含一個狀態參數n,即System.exit(n)
。這實際上是一個約定值,若是爲0則表示正常關閉,而非0則表示非正常關閉。這裏咱們從JDK源碼看下不一樣狀態都是怎麼處理的。html
先看System類的exit方法以下,能夠看到它是間接調用了Runtime對象的exit方法。java
public static void exit(int status) {
Runtime.getRuntime().exit(status);
}複製代碼
而Runtime的exit方法以下,先使用SecurityManager檢查是否有關閉JVM的權限,容許執行則調用Shutdown的exit方法。bash
public void exit(int status) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkExit(status);
}
Shutdown.exit(status);
}複製代碼
進入到Shutdown類的exit方法,Java層面還有本身的狀態state,它可能值爲RUNNING、HOOKS和FINALIZERS,能夠看到裏面的主要邏輯是:併發
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();
}複製代碼
執行JVM是經過halt方法實現,這時System.exit(n)
的狀態n繼續往下傳遞,最終是調用了一個本地的halt0方法。jvm
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。ui
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() 來退出。spa
如下是廣告和相關閱讀操作系統
========廣告時間========
鄙人的新書《Tomcat內核設計剖析》已經在京東銷售了,有須要的朋友能夠到 item.jd.com/12185360.ht… 進行預約。感謝各位朋友。
=========================
相關閱讀:
從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
關注打賞: