今天就跟大家聊聊有關(guān)ShutdownHook如何讓應(yīng)用優(yōu)雅的停止,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

成都創(chuàng)新互聯(lián)服務(wù)項目包括高淳網(wǎng)站建設(shè)、高淳網(wǎng)站制作、高淳網(wǎng)頁制作以及高淳網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,高淳網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到高淳省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
對于應(yīng)用,停止的時候一般都會把環(huán)境和數(shù)據(jù)恢復(fù)到運行前的樣子,和單元測試時tearDown要做的效果基本類似。而為了實現(xiàn)停止時恢復(fù)現(xiàn)場,英文中有個特定的描述:
shutdown gracefully
在Java中,為了實現(xiàn)gracefully shutdown,有一個特定的接口可供使用,就是我們今天要提到的shutdown hook。它與回調(diào)函數(shù)功能類似,文檔中對其描述如下:
關(guān)閉鉤子 只是一個已初始化但尚未啟動的線程。虛擬機(jī)開始啟用其關(guān)閉序列時,它會以某種未指定的順序啟動所有已注冊的關(guān)閉鉤子,并讓它們同時運行。運行完所有的鉤子后,如果已啟用退出終結(jié),那么虛擬機(jī)接著會運行所有未調(diào)用的終結(jié)方法。最后,虛擬機(jī)會暫停。注意,關(guān)閉序列期間會繼續(xù)運行守護(hù)線程,如果通過調(diào)用
exit方法來發(fā)起關(guān)閉序列,那么也會繼續(xù)運行非守護(hù)線程。
要為應(yīng)用添加shutdownHook,需要做的只是這樣的下操作:
Runtime.getRuntime().addShutdownHook(new Thread() {public void run() { /* my shutdown code here */ } });
向addShutdownHook方法傳入的Thread,其run方法即為自定義的shutdown時清理邏輯。
JDK內(nèi)部,是通過一個Map來保存所有添加的ShutdownHook,在被觸發(fā)時執(zhí)行。
public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);static synchronized void add(Thread hook) {
hooks.put(hook, hook);
}private static IdentityHashMap<Thread, Thread> hooks;hooks = new IdentityHashMap<>();
那這個shutdownHook一般是在什么時候會被調(diào)用呢?
我們看JDK的文檔中描述,對于兩類事件Java虛擬機(jī)會退出:
Java 虛擬機(jī)會為了響應(yīng)以下兩類事件而關(guān)閉:
程序正常退出,這發(fā)生在最后的非守護(hù)線程退出時,或者在調(diào)用
exit(等同于System.exit)方法時。或者,為響應(yīng)用戶中斷而終止 虛擬機(jī),如鍵入 ^C;或發(fā)生系統(tǒng)事件,比如用戶注銷或系統(tǒng)關(guān)閉。
在Java虛擬機(jī)退出的時候,這些設(shè)置的shutdownHook會被并行的調(diào)用。但需要注意的是,對于非正常方式退出Java虛擬機(jī),例如殺進(jìn)程,系統(tǒng)斷電等,這些情況下,shutdownHook不會被執(zhí)行。
我們來看,在Tomcat內(nèi)部,是如何使用ShutdownHook的。
Catalina類內(nèi)部,在服務(wù)器內(nèi)部各個組件啟動完畢后,有這樣一段代碼
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);}
和我們在本文開頭看到的一樣,他注冊了一個ShutdownHook。這個hook的內(nèi)容如下:
/**
* Shutdown hook which will perform a clean shutdown of Catalina if needed.
*/
protected class CatalinaShutdownHook extends Thread {
public void run() {
try {
if (getServer() != null) {
Catalina.this.stop();
}
} catch (Throwable ex) {
} finally {
}
}
}
看就是在shutdown的時候通過調(diào)用應(yīng)用服務(wù)器的stop方法,來shutdown gracefully。
而我們一般停止Tomcat會通過調(diào)用shutdown腳本的方式進(jìn)行,這個時候,腳本實質(zhì)上去執(zhí)行了應(yīng)用服務(wù)器的stop方法來進(jìn)行停止,而不是被shutdownHook來反調(diào)過來的。
因此,在讀源碼時,你會發(fā)現(xiàn)代碼中有這樣的內(nèi)容:
/**
* Stop an existing server instance.
*/
public void stop() {
try {
// Remove the ShutdownHook first so that server.stop()
// doesn't get invoked twice
if (useShutdownHook) {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);}
我們看到,在停止Server的時候,會先執(zhí)行removeShutdownHook的操作,注釋里寫的明白,是為了防止server和stop被執(zhí)行兩次。
哪種情況下會被執(zhí)行兩次呢?
當(dāng)使用catalina的shutdown腳本停止Server時,這個方法并不是從shutdownHook調(diào)用過來,此時,shutdownHook還沒有執(zhí)行,所以在JVM退出的時候,shutdownHook會被觸發(fā)。如果此處還沒去remove掉的話,就還會調(diào)用過來。這一點在我們自己開發(fā)應(yīng)用時需要注意借鑒一下。
看到這里,希望你不要說然并卵。
當(dāng)然,如果你已經(jīng)脫口而出,那...
我找了例子證明,你已經(jīng)在不知不覺中使用了shutdownHook,例如你在輸出日志的時候,以下代碼是JDK的LogManager中的一部分,我們看到,其構(gòu)造方法中直接會添加一個名為Cleaner的shutdownHook。
private LogManager(Void checked) {
// Add a shutdown hook to close the global handlers.
try {
Runtime.getRuntime().addShutdownHook(new Cleaner());
} catch (IllegalStateException e) {
// If the VM is already shutting down,
// We do not need to register shutdownHook.
}
}public void run() {
// This is to ensure the LogManager.<clinit> is completed
// before synchronized block. Otherwise deadlocks are possible.
LogManager mgr = manager;
// Do a reset to close all active handlers.
reset();
}
我們自己添加shutdownHook的時候,需要注意的是:
在內(nèi)部不要寫耗時的操作,也不要寫容易引起死鎖的操作。多個ShutdownHook之間如果存在資源競爭而死鎖,那應(yīng)用就停止不了了。
看完上述內(nèi)容,你們對ShutdownHook如何讓應(yīng)用優(yōu)雅的停止有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。
網(wǎng)頁標(biāo)題:ShutdownHook如何讓應(yīng)用優(yōu)雅的停止
瀏覽地址:http://chinadenli.net/article38/jpcepp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、網(wǎng)站維護(hù)、網(wǎng)站設(shè)計、企業(yè)建站、靜態(tài)網(wǎng)站、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)