下面的程序在尋常的Hello world程序中添加了一段不尋常的曲折操作。那么,它將會打印出什么呢?
public class HelloGoodbye {
public static void main(String[] args) {
try {
System.out.println("Hello world");
System.exit(0);
} finally {
System.out.println("Goodbye world");
}
}
}
這個程序包含兩個println語句:一個在try語句塊中,另一個在相應的finally語句塊中。try語句塊執(zhí)行它的println語句,并且通過調用System.exit來提前結束執(zhí)行。在此時,你可能希望控制權會轉交給finally語句塊。然而,如果你運行該程序,就會發(fā)現它永遠不會說再見:它只打印了Hello world。這是否違背了謎題36中所解釋的原則呢?
不論try語句塊的執(zhí)行是正常地還是意外地結束,finally語句塊確實都會執(zhí)行。然而在這個程序中,try語句塊根本就沒有結束其執(zhí)行過程。System.exit方法將停止當前線程和所有其他當場死亡的線程。finally子句的出現并不能給予線程繼續(xù)去執(zhí)行的特殊權限。
當System.exit被調用時,虛擬機在關閉前要執(zhí)行兩項清理工作。首先,它執(zhí)行所有的關閉掛鉤操作,這些掛鉤已經注冊到了Runtime.addShutdownHook上。這對于釋放VM之外的資源將很有幫助。務必要為那些必須在VM退出之前發(fā)生的行為關閉掛鉤。下面的程序版本示范了這種技術,它可以如我們所期望地打印出Hello world和Goodbye world:
public class HelloGoodbye1 {
public static void main(String[] args) {
System.out.println("Hello world");
Runtime.getRuntime().addShutdownHook(
new Thread() {
public void run() {
System.out.println("Goodbye world");
}
});
System.exit(0);
}
}
VM執(zhí)行在System.exit被調用時執(zhí)行的第二個清理任務與終結器有關。如果System.runFinalizerOnExit或它的魔鬼雙胞胎Runtime.runFinalizersOnExit被調用了,那么VM將在所有還未終結的對象上面調用終結器。這些方法很久以前就已經過時了,而且其原因也很合理。無論什么原因,永遠不要調用System.runFinalizersOnExit和Runtime.runFinalizersOnExit:它們屬于Java類庫中最危險的方法之一[ThreadStop]。調用這些方法導致的結果是,終結器會在那些其他線程正在并發(fā)操作的對象上面運行,從而導致不確定的行為或導致死鎖。
總之,System.exit將立即停止所有的程序線程,它并不會使finally語句塊得到調用,但是它在停止VM之前會執(zhí)行關閉掛鉤操作。當VM被關閉時,請使用關閉掛鉤來終止外部資源。通過調用System.halt可以在不執(zhí)行關閉掛鉤的情況下停止VM,但是這個方法很少使用。
public class HelloGoodbye {
public static void main(String[] args) {
try {
System.out.println("Hello world");
System.exit(0);
} finally {
System.out.println("Goodbye world");
}
}
}
這個程序包含兩個println語句:一個在try語句塊中,另一個在相應的finally語句塊中。try語句塊執(zhí)行它的println語句,并且通過調用System.exit來提前結束執(zhí)行。在此時,你可能希望控制權會轉交給finally語句塊。然而,如果你運行該程序,就會發(fā)現它永遠不會說再見:它只打印了Hello world。這是否違背了謎題36中所解釋的原則呢?
不論try語句塊的執(zhí)行是正常地還是意外地結束,finally語句塊確實都會執(zhí)行。然而在這個程序中,try語句塊根本就沒有結束其執(zhí)行過程。System.exit方法將停止當前線程和所有其他當場死亡的線程。finally子句的出現并不能給予線程繼續(xù)去執(zhí)行的特殊權限。
當System.exit被調用時,虛擬機在關閉前要執(zhí)行兩項清理工作。首先,它執(zhí)行所有的關閉掛鉤操作,這些掛鉤已經注冊到了Runtime.addShutdownHook上。這對于釋放VM之外的資源將很有幫助。務必要為那些必須在VM退出之前發(fā)生的行為關閉掛鉤。下面的程序版本示范了這種技術,它可以如我們所期望地打印出Hello world和Goodbye world:
public class HelloGoodbye1 {
public static void main(String[] args) {
System.out.println("Hello world");
Runtime.getRuntime().addShutdownHook(
new Thread() {
public void run() {
System.out.println("Goodbye world");
}
});
System.exit(0);
}
}
VM執(zhí)行在System.exit被調用時執(zhí)行的第二個清理任務與終結器有關。如果System.runFinalizerOnExit或它的魔鬼雙胞胎Runtime.runFinalizersOnExit被調用了,那么VM將在所有還未終結的對象上面調用終結器。這些方法很久以前就已經過時了,而且其原因也很合理。無論什么原因,永遠不要調用System.runFinalizersOnExit和Runtime.runFinalizersOnExit:它們屬于Java類庫中最危險的方法之一[ThreadStop]。調用這些方法導致的結果是,終結器會在那些其他線程正在并發(fā)操作的對象上面運行,從而導致不確定的行為或導致死鎖。
總之,System.exit將立即停止所有的程序線程,它并不會使finally語句塊得到調用,但是它在停止VM之前會執(zhí)行關閉掛鉤操作。當VM被關閉時,請使用關閉掛鉤來終止外部資源。通過調用System.halt可以在不執(zhí)行關閉掛鉤的情況下停止VM,但是這個方法很少使用。