最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java的finally塊居然沒執(zhí)行的6種問題解決

 更新時(shí)間:2026年05月01日 09:56:24   作者:阿橙的百寶箱  
本文探討了Java中try-catch-finally結(jié)構(gòu)下finally塊可能不執(zhí)行的情況,并分析了JVM層面的原理,文章列出了6種特殊情況,下面就來詳細(xì)的介紹一下

引言

在Java異常處理機(jī)制中,try-catch-finally是最常用的結(jié)構(gòu)之一。開發(fā)者普遍認(rèn)為finally塊是"一定會(huì)執(zhí)行"的代碼區(qū)域,常用于資源釋放、狀態(tài)清理等關(guān)鍵操作。然而,在實(shí)際開發(fā)中,某些情況下finally塊可能不會(huì)執(zhí)行——這是一個(gè)容易被忽視但可能導(dǎo)致嚴(yán)重問題的"巨坑"。本文將深入剖析這些特殊情況,從JVM層面解釋原理,并提供實(shí)際案例和解決方案。

一、finally塊的"絕對(duì)執(zhí)行"神話

1.1 常規(guī)認(rèn)知

根據(jù)Oracle官方文檔說明:

"The finally block always executes when the try block exits."

大多數(shù)教程都強(qiáng)調(diào)finally會(huì)在以下情況執(zhí)行:

  • try塊正常完成
  • catch塊捕獲異常
  • catch塊拋出新異常

1.2 現(xiàn)實(shí)挑戰(zhàn)

在實(shí)際生產(chǎn)環(huán)境中,我們遇到過如下場(chǎng)景:

try {
    System.out.println("Try block");
    System.exit(0); // 注意這里
} finally {
    System.out.println("Finally block"); // 這行不會(huì)執(zhí)行
}

這段代碼的輸出只有"Try block",顛覆了開發(fā)者對(duì)finally的常規(guī)認(rèn)知。

二、finally不執(zhí)行的6種特殊情況

2.1 JVM強(qiáng)制退出(System.exit)

當(dāng)調(diào)用以下方法時(shí):

System.exit(int status)
Runtime.getRuntime().exit(int status)

JVM會(huì)立即終止,不執(zhí)行任何后續(xù)代碼。這是設(shè)計(jì)上的行為,因?yàn)閑xit意味著立即停止所有線程。

  • 深度原理*:查看HotSpot源碼(jni.cpp)可以看到:
JNI_ENTRY(void, jni_Exit(JNIEnv *env, jint code))
  before_exit(thread);
  vm_exit(code);
JNI_END

其中vm_exit()會(huì)直接調(diào)用os::exit()終止進(jìn)程。

2.2 JVM崩潰(OutOfMemoryError等)

當(dāng)發(fā)生下列不可恢復(fù)錯(cuò)誤時(shí):

  • OutOfMemoryError
  • StackOverflowError
  • InternalError

此時(shí)JVM已處于不穩(wěn)定狀態(tài),無法保證finally執(zhí)行。

  • 案例*:
try {
    int[] arr = new int[Integer.MAX_VALUE]; // OOM
} finally {
    System.out.println("This won't print");
}

2.3 線程被中斷(Thread.stop)

雖然已被廢棄,但Thread.stop()仍會(huì)導(dǎo)致finally跳過:

Thread t = new Thread(() -> {
    try {
        Thread.sleep(1000);
    } finally {
        System.out.println("Unreachable");
    }
});
t.start();
t.stop(); // Deprecated but still exists

2.4 守護(hù)線程與JVM退出

當(dāng)所有非守護(hù)線程結(jié)束時(shí),JVM會(huì)立即退出,不等待守護(hù)線程的finally:

Thread daemon = new Thread(() -> {
    try {
        Thread.sleep(500);
    } finally {
        System.out.println("Daemon finally"); // May not execute
    }
});
daemon.setDaemon(true);
daemon.start();

2.5 try塊無限循環(huán)/阻塞

如果try塊中有無限循環(huán)或不可中斷的阻塞操作:

try {
    while(true) { /* infinite loop */ }
} finally {
    System.out.println("Never reached");
}

2.6 finally內(nèi)的異常未被捕獲(Java7+)

在Java7之前,若finally拋出異常會(huì)覆蓋try/catch的異常。但在現(xiàn)代版本中:

try { 
    throw new RuntimeException("From try"); 
} finally { 
    throw new RuntimeException("From finally"); 
}
// Only "From finally" is propagated

三、底層機(jī)制解析

3.1 JVM字節(jié)碼視角

觀察以下代碼編譯后的字節(jié)碼:

// Java源碼:
void example() {
    try { mayThrow(); }
    finally { cleanup(); }
}

// Bytecode:
0: aload_0
1: invokevirtual #7 // mayThrow()
4: aload_0        
5: invokevirtual #9 // cleanup()
8: goto          20
11: astore_1      // exception handler starts here...
12: aload_0       
13: invokevirtual #9 // cleanup()
16: aload_1       
17: athrow        
20: return        

關(guān)鍵發(fā)現(xiàn):編譯器會(huì)復(fù)制finally代碼到多個(gè)位置(正常路徑和異常路徑)。

3.2 JLS規(guī)范解讀

根據(jù)Java Language Specification §14.20.2:

"A finally clause is executed after execution of the try block and any catch clauses... unless the thread executing them terminates abruptly."

明確指出在以下情況不保證執(zhí)行:

  1. JVM退出(abrupt JVM termination)
  2. 線程死亡(thread death)
  3. 外部kill信號(hào)(external kill signals)

四、防御性編程實(shí)踐

4.1 ShutdownHook替代方案

對(duì)于需要確保執(zhí)行的清理操作:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    System.out.println("Guaranteed cleanup before JVM exit");
}));

注意:同樣無法處理kill -9等強(qiáng)制終止信號(hào)。

4.2 try-with-resources改進(jìn)

對(duì)于資源管理優(yōu)先使用:

try (InputStream is = new FileInputStream("/path")) {
    // auto-close guaranteed if normal execution path
}

優(yōu)于手動(dòng)finally關(guān)閉的方式。

4.3 Critical Section保護(hù)

在多線程環(huán)境中:

Lock lock = new ReentrantLock();
lock.lock();
try { /* critical section */ }
finally { 
    if(lock.isHeldByCurrentThread()) 
        lock.unlock(); 
}

需額外檢查避免鎖泄露。

五、生產(chǎn)環(huán)境最佳實(shí)踐

  1. 避免System.exit:改用異常傳遞錯(cuò)誤狀態(tài)
  2. OOM防護(hù):為關(guān)鍵操作設(shè)置內(nèi)存閾值
    if(Runtime.getRuntime().freeMemory() < threshold) {...}
    
  3. 守護(hù)線程標(biāo)注:明確標(biāo)記非關(guān)鍵任務(wù)
  4. 雙重保障機(jī)制:重要狀態(tài)持久化+定期檢查
  5. 監(jiān)控集成:通過JMX/JVMTI監(jiān)控關(guān)鍵流程

六、總結(jié)反思

理解Java異常處理的真實(shí)行為比記住語(yǔ)法規(guī)則更重要。正如Brian Goetz所言:

"The language specification defines what behavior is guaranteed, not what behavior you might observe in all cases."

作為開發(fā)者應(yīng)該:

  1. 認(rèn)清語(yǔ)言規(guī)范與實(shí)際實(shí)現(xiàn)的差異
  2. critical操作要有fallback機(jī)制
  3. finally不是銀彈,系統(tǒng)設(shè)計(jì)需考慮邊界條件

這個(gè)"巨坑"的本質(zhì)是對(duì)確定性的過度假設(shè)。在分布式系統(tǒng)、云原生環(huán)境下,我們需要采用更健壯的模式如Circuit Breaker、Saga Pattern等來補(bǔ)充語(yǔ)言層面的不足。

到此這篇關(guān)于Java的finally塊居然沒執(zhí)行的6種問題解決的文章就介紹到這了,更多相關(guān)Java finally塊執(zhí)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring實(shí)戰(zhàn)之Qualifier注解用法示例

    Spring實(shí)戰(zhàn)之Qualifier注解用法示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之Qualifier注解用法,結(jié)合實(shí)例形式詳細(xì)分析了spring Qualifier注解相關(guān)配置、定義與使用方法,需要的朋友可以參考下
    2019-12-12
  • mybatis簡(jiǎn)單resultMap使用詳解

    mybatis簡(jiǎn)單resultMap使用詳解

    resultMap是Mybatis最強(qiáng)大的元素,它可以將查詢到的復(fù)雜數(shù)據(jù)(比如查詢到幾個(gè)表中數(shù)據(jù))映射到一個(gè)結(jié)果集當(dāng)中。這篇文章主要介紹了mybatis簡(jiǎn)單resultMap使用詳解的相關(guān)資料,需要的朋友可以參考下
    2021-04-04
  • 淺談Java 類中各成分加載順序和內(nèi)存中的存放位置

    淺談Java 類中各成分加載順序和內(nèi)存中的存放位置

    下面小編就為大家?guī)硪黄獪\談Java 類中各成分加載順序和內(nèi)存中的存放位置。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • 一篇文章搞定數(shù)據(jù)庫(kù)連接池

    一篇文章搞定數(shù)據(jù)庫(kù)連接池

    數(shù)據(jù)庫(kù)連接池在編寫應(yīng)用服務(wù)是經(jīng)常需要用到的模塊,太過頻繁的連接數(shù)據(jù)庫(kù)對(duì)服務(wù)性能來講是一個(gè)瓶頸,使用緩沖池技術(shù)可以來消除這個(gè)瓶頸,本文就來介紹Java常見的幾種,感興趣的可以了解一下
    2021-07-07
  • IDEA啟動(dòng)Tomcat報(bào)Unrecognized option: --add-opens=java.base/java.lang=ALL-UNNAMED的解決方法

    IDEA啟動(dòng)Tomcat報(bào)Unrecognized option: --add-opens=java

    這篇文章主要為大家介紹了解決IDEA啟動(dòng)Tomcat報(bào)Unrecognized option: --add-opens=java.base/java.lang=ALL-UNNAMED的方法,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • 手把手教你k8s部署springboot服務(wù)

    手把手教你k8s部署springboot服務(wù)

    本文主要介紹了手把手教你k8s部署springboot服務(wù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • IntelliJ IDEA安裝插件阿里巴巴Java開發(fā)手冊(cè)(Alibaba Java Coding Guidelines)

    IntelliJ IDEA安裝插件阿里巴巴Java開發(fā)手冊(cè)(Alibaba Java Coding Guidelines

    這篇文章主要介紹了IntelliJ IDEA安裝插件阿里巴巴Java開發(fā)手冊(cè)(Alibaba Java Coding Guidelines),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • mybatis創(chuàng)建項(xiàng)目報(bào)Invalid?bound?statement?(not?found)錯(cuò)誤解決方法

    mybatis創(chuàng)建項(xiàng)目報(bào)Invalid?bound?statement?(not?found)錯(cuò)誤解決方法

    使用MyBatis能夠幫助我們將SQL語(yǔ)句和Java代碼分離,這篇文章主要給大家介紹了關(guān)于mybatis創(chuàng)建項(xiàng)目報(bào)Invalid?bound?statement?(not?found)錯(cuò)誤的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • java中l(wèi)ambda(函數(shù)式編程)一行解決foreach循環(huán)問題

    java中l(wèi)ambda(函數(shù)式編程)一行解決foreach循環(huán)問題

    這篇文章主要介紹了java中l(wèi)ambda(函數(shù)式編程)一行解決foreach循環(huán)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java與WebUploader相結(jié)合實(shí)現(xiàn)文件上傳功能(實(shí)例代碼)

    Java與WebUploader相結(jié)合實(shí)現(xiàn)文件上傳功能(實(shí)例代碼)

    這篇文章主要介紹了Java結(jié)合WebUploader實(shí)現(xiàn)文件上傳功能,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03

最新評(píng)論

湖南省| 宜兰市| 安福县| 溧水县| 郓城县| 绵竹市| 开江县| 万山特区| 隆德县| 木兰县| 邓州市| 富顺县| 南木林县| 宾阳县| 黄梅县| 绍兴市| 宁阳县| 峨眉山市| 安平县| 江华| 边坝县| 鹤山市| 松阳县| 葫芦岛市| 桐庐县| 海盐县| 皋兰县| 潜江市| 景宁| 七台河市| 阿合奇县| 盐边县| 元朗区| 始兴县| 桓台县| 成安县| 贡嘎县| 明星| 南岸区| 玉溪市| 舒兰市|