线程钩子ShutDown Hook与Finally

  • Post author:
  • Post category:其他




线程钩子



前言

某些情况下,Finally无法释放线程资源,所以我们需要使用线程钩子释放。在线上对于分布式锁的释放,一般在Finally里进行,但是应用重启时的脚本使用的是kill-15指令关机,此时Finally里面的代码不会被执行,导致分布式锁无法释放。


Finally一定会执行么?



线程基础知识

  1. java中线程状态与转换关系如下图:

    在这里插入图片描述

其中箭头旁边的标注代表执行的线程方法。

[外链图片转存中…(img-mQRWdhf5-1601360975262)]

从running态转为Block阻塞态有三种方法,这三种方法的区别是:

  • sleep 主动释放CPU,但不会释放同步锁等资源。主要用于暂停。

  • wait

    是Object 的方法,调用时会放弃对象锁,进入等待序列,直到调用

    notify

    或者

    notifyAll()

    。主要用于线程间的通信。

  • suspend()

    方法和

    resume()

    方法因为容易死锁已经被废弃。如果一个线程

    suspend

    期间持有系统资源的锁,其它线程必须等

    resume

    之后才能获取;此时如果本线程正等其它线程持有的系统资源才能

    resume

    则死锁发生。



线程钩子

JVM可以正常关闭也可以强行关闭。正常关闭包括:

  • 最后一个线程结束时
  • 调用

    System.exit()
  • 通过平台的方法关闭:发送 SIGTERM,或SIGINT(CTRL+C)信号)。但是不包括SIGKILL(kill-9)信号。


在正常关闭时,JVM会调用已经注册的线程钩子(ShutDown Hook)。利用这个特性,我们可以保证在外届执行kill-15等指令退出程序时,使用线程钩子释放资源。

使用线程钩子时应该注意以下事项:

  • JVM不能保证钩子的调用顺序
  • 强行关闭如调用Runtime.halt或者kill-9 时,线程钩子不能执行
  • 钩子将并发执行,所以钩子应该注意线程安全问题。


举个例子🌰:

当我们正常关闭程序时 程序将输出:

Shutdown Hook is running !

public class ShutDownHook 
{ 
  public static void main(String[] args) 
  { 
  
    Runtime.getRuntime().addShutdownHook(new Thread() 
    { 
      public void run() 
      { 
        System.out.println("Shutdown Hook is running !"); 
      } 
    }); 
    System.out.println("Application Terminating ..."); 
  } 
}



KILL 指令

选项

-s sig 信号名称。

-n sig 信号名称对应的数字。

-l 列出信号名称。如果在该选项后提供了数字那么假设它是信号名称对应的数字。

-L 等价于-l选项。

例子:

[user2@pc] kill -l 9
KILL
列出所有信号名称:
[user2@pc] kill -l
1. SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
2. SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
3. SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
4. SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
5. SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
6. SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
7. SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
8. SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
9. SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
10. SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
11. SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
12. SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
13. SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
14. SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
15. SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
16. SIGRTMAX-1  64) SIGRTMAX
下面是常用的信号。
只有第9种信号(SIGKILL)才可以无条件终止进程,其他信号进程都有权利忽略。
HUP     1    终端挂断
INT     2    中断(同 Ctrl + C)
QUIT    3    退出(同 Ctrl + \)
KILL    9    强制终止
TERM   15    终止
CONT   18    继续(与STOP相反,fg/bg命令)
STOP   19    暂停(同 Ctrl + Z)



版权声明:本文为h2453532874原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。