自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何優(yōu)雅的關(guān)閉JVM?

云計(jì)算 虛擬化
程序的啟動(dòng)很簡(jiǎn)單,啟動(dòng)的時(shí)候通常會(huì)做一些預(yù)加載資源的操作。但是有時(shí)候關(guān)閉的時(shí)候,啟動(dòng)的時(shí)候預(yù)加載的資源并沒有完全清理干凈,因此可以使用鉤子函數(shù)來完成。

[[376925]]

前言

1、基本概述

程序的啟動(dòng)很簡(jiǎn)單,啟動(dòng)的時(shí)候通常會(huì)做一些預(yù)加載資源的操作。但是有時(shí)候關(guān)閉的時(shí)候,啟動(dòng)的時(shí)候預(yù)加載的資源并沒有完全清理干凈,因此可以使用鉤子函數(shù)來完成。

2、JVM關(guān)閉的場(chǎng)景分類

直接看一張圖吧,本圖來自博客園的BarryWang,特在此說明。

從上面可以看到,JVM關(guān)閉主要分為了三類,第一種是正常的關(guān)閉,第二種是異常關(guān)閉的情況,第三種是強(qiáng)制關(guān)閉的情況。對(duì)于前兩種方式我們可以使用鉤子函數(shù)優(yōu)雅的關(guān)閉,但是強(qiáng)制關(guān)閉的時(shí)候鉤子函數(shù)并不起作用。

有了這些概念,我們直接使用一個(gè)案例進(jìn)行演示,再進(jìn)行分析。

一、代碼演示鉤子函數(shù)

1、JVM正常關(guān)閉

直接看代碼吧,

  1. public class Test { 
  2.  public void start(){ 
  3.   Runtime.getRuntime().addShutdownHook(new Thread(()->  
  4.     System.out.println("鉤子函數(shù)被執(zhí)行,可以在這里關(guān)閉資源"
  5.   )); 
  6.  } 
  7.  public static void main(String[] args) throws Exception{ 
  8.   new Test().start(); 
  9.   System.out.println("主應(yīng)用程序在執(zhí)行"); 
  10.  } 
  11. //控制臺(tái)輸出 
  12. //主應(yīng)用程序在執(zhí)行 
  13. //鉤子函數(shù)被執(zhí)行,可以在這里關(guān)閉資源 

看控制臺(tái)打印,可以發(fā)現(xiàn),主應(yīng)用程序執(zhí)行完之后就會(huì)調(diào)用鉤子函數(shù),接下來就會(huì)正式的關(guān)閉JVM。

2、異常關(guān)閉

還是直接看代碼演示,這里我們演示異常關(guān)閉的第二種OOM的情況,我們可以先設(shè)置堆的大小為20M,然后在代碼中創(chuàng)建一個(gè)500M的對(duì)象,這樣就會(huì)OOM。參數(shù)是-Xmx20M;

  1. public class Test { 
  2.  public void start(){ 
  3.   Runtime.getRuntime().addShutdownHook(new Thread(()->  
  4.     System.out.println("鉤子函數(shù)被執(zhí)行,可以在這里關(guān)閉資源"
  5.   )); 
  6.  } 
  7.  public static void main(String[] args) throws Exception{ 
  8.   new Test().start(); 
  9.   System.out.println("主應(yīng)用程序在執(zhí)行"); 
  10.   Runtime.getRuntime().halt(1); 
  11.   byte[] b = new byte[500*1024*1024]; 
  12.  } 
  13. //控制臺(tái)輸出 
  14. //主應(yīng)用程序在執(zhí)行 
  15. //鉤子函數(shù)被執(zhí)行,可以在這里關(guān)閉資源 

從控制臺(tái)可以看出,鉤子函數(shù)在異常關(guān)閉的時(shí)候依然會(huì)被調(diào)用。

3、強(qiáng)制關(guān)閉

這里我們使用Runtime.getRuntime().halt()來演示強(qiáng)勢(shì)關(guān)閉。這個(gè)方法和System.exit的區(qū)別是,System.exit會(huì)執(zhí)行鉤子函數(shù),但是Runtime.getRuntime().halt()不會(huì)。

  1. public class Test { 
  2.  public void start(){ 
  3.   Runtime.getRuntime().addShutdownHook(new Thread(()->  
  4.     System.out.println("鉤子函數(shù)被執(zhí)行,可以在這里關(guān)閉資源"
  5.   )); 
  6.  } 
  7.  public static void main(String[] args) throws Exception{ 
  8.   new Test().start(); 
  9.   System.out.println("主應(yīng)用程序在執(zhí)行"); 
  10.   Runtime.getRuntime().halt(1); 
  11.  } 
  12. //控制臺(tái)輸出 
  13. //主應(yīng)用程序在執(zhí)行 

從上面代碼的輸出可以看出,調(diào)用了Runtime.getRuntime().halt(1)就會(huì)強(qiáng)制關(guān)閉JVM,鉤子函數(shù)來不及執(zhí)行就關(guān)閉了。而使用System.exit依然會(huì)執(zhí)行。所以一般使用System.exit來關(guān)閉JVM。

4、移除鉤子函數(shù)

上面演示了鉤子函數(shù)的作用,有時(shí)候我們想移除也比較簡(jiǎn)單。

  1. public class Test { 
  2.  public static void main(String[] args) throws Exception{ 
  3.   //new Test().start(); 
  4.   Thread willNotRun = new Thread(() ->  
  5.    System.out.println("Won't run!")); 
  6.   Runtime.getRuntime().addShutdownHook(willNotRun); 
  7.   System.out.println("主應(yīng)用程序在執(zhí)行"); 
  8.   Runtime.getRuntime().removeShutdownHook(willNotRun); 
  9.  } 
  10. //控制臺(tái)輸出 
  11. //主應(yīng)用程序在執(zhí)行 

OK,鉤子函數(shù)的基本操作就寫到這,使用起來比較簡(jiǎn)單,不過我之前看過Spring的啟動(dòng)流程,所以又去那個(gè)啟動(dòng)流程看了一波,發(fā)現(xiàn)也使用到了鉤子函數(shù)。

二、典型應(yīng)用場(chǎng)景

1、Spring使用

Spring在關(guān)閉上下文的時(shí)候,可以使用鉤子函數(shù)來關(guān)閉殘留的資源。方法是使用ApplicationContext注冊(cè)一個(gè)鉤子函數(shù)即可。

  1. ApplicationContext.registerShutdownHook(); 
  2. //上面的這句代碼可以分析進(jìn)去看看 
  3. public void registerShutdownHook() { 
  4.     if (this.shutdownHook == null) { 
  5.       this.shutdownHook = new Thread() { 
  6.         @Override 
  7.         public void run() { 
  8.           //Spring正常關(guān)閉 
  9.           doClose(); 
  10.         } 
  11.       }; 
  12.       //調(diào)用鉤子函數(shù)關(guān)閉殘留資源 
  13.       Runtime.getRuntime().addShutdownHook(this.shutdownHook); 
  14.     } 

從源碼可以看出,Spring其實(shí)也是調(diào)用了Java的鉤子函數(shù)進(jìn)行關(guān)閉的。

2、其他使用

我在很多博客中也看到了spark和hadoop的關(guān)閉,由于我沒看過源碼,所以這里我說一下結(jié)論,對(duì)于其他的使用場(chǎng)景,基本上也是調(diào)用了Java的鉤子函數(shù)來執(zhí)行的。

結(jié)論

在關(guān)閉JVM的時(shí)候,我們可以封裝鉤子函數(shù)去優(yōu)雅的關(guān)閉線程。不過在使用的時(shí)候還需要注意以下幾個(gè)方面:

1、鉤子函數(shù)本質(zhì)是個(gè)線程

多個(gè)鉤子會(huì)并發(fā)執(zhí)行,JVM并不保證它們的執(zhí)行順序;因此最好是在一個(gè)鉤子中執(zhí)行一系列操作。

2、鉤子中不能再新建鉤子

在關(guān)閉鉤子中,不能執(zhí)行注冊(cè)、移除鉤子的操作,否則JVM拋出 IllegalStateException。也不能使用System.exit(),前面提到System.exit()會(huì)觸發(fā)鉤子函數(shù)的執(zhí)行,但是Runtime.halt()可以,因?yàn)镽untime.halt()可以強(qiáng)制關(guān)閉。

3、鉤子里最好不要有耗時(shí)操作

鉤子函數(shù)主要用于關(guān)閉殘留資源,因此不要有一些耗時(shí)的操作。

OK,先寫到這。相關(guān)的經(jīng)驗(yàn)方法,并推薦幾本關(guān)于體驗(yàn)、思考的書籍。希望對(duì)同學(xué)們有所啟發(fā)。

本文轉(zhuǎn)載自微信公眾號(hào)「愚公要移山」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系愚公要移山公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 愚公要移山
相關(guān)推薦

2021-03-28 09:17:18

JVM場(chǎng)景鉤子函數(shù)

2022-04-11 08:17:07

JVMJava進(jìn)程

2024-11-13 16:37:00

Java線程池

2017-12-19 10:03:44

JavaLinux代碼

2021-12-06 09:57:25

容器Linux信號(hào)

2025-01-13 06:00:00

Go語言gRPC

2022-09-08 07:32:56

JDK7程序管理

2021-04-20 08:00:31

Redisson關(guān)閉訂單支付系統(tǒng)

2019-11-18 15:50:11

AjaxJavascript前端

2025-02-12 00:21:44

Java并發(fā)編程

2023-12-20 10:04:45

線程池Java

2020-10-16 11:48:06

服務(wù)器系統(tǒng)運(yùn)維

2015-11-26 10:53:45

LinuxWindowsMac OS

2017-07-26 11:32:50

NETRabbitMQ系統(tǒng)集成

2023-10-07 08:41:42

JavaJVM

2023-12-04 08:46:40

Go標(biāo)準(zhǔn)庫

2023-10-20 08:00:55

PodRainbow部署

2021-11-15 06:56:45

系統(tǒng)運(yùn)行空指針

2022-02-18 17:34:47

數(shù)組多維五維數(shù)組

2023-06-16 09:08:39

ReactContextRFC
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)