Hook线程以及捕获线程执行异常

1、什么是Hook线程?

Hook线程即钩子线程,JVM进程的退出时由于JVM进程中没有活跃的非守护线程,或者收到了系统中断信号,向JVM程序注入一个Hook线程,在JVM进程退出的时候,Hook线程会启动执行,通过RunTime可以为JVM注入多个Hook线程。

public class ThreadHook {
    
    

    public static void main( String[] args ) {
    
    
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
    
    
            try {
    
    
                System.out.println("The hook thread 1 is running");
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }

            System.out.println("The hook thread 1 will exit");

        },"hook-thread1"));

        Runtime.getRuntime().addShutdownHook(new Thread(()->{
    
    
            try {
    
    
                System.out.println("The hook thread 2 is running");
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }

            System.out.println("The hook thread 2 will exit");

        },"hook-thread2"));

        System.out.println("The  progran will is stopping");
    }
}

2.Hook线程实战

在我们的开发中 经常会遇到Hook线程,比如为了防止某个程序被重复启动,在进程启动时 会创建一个lock文件,进程收到中断信号的时候会删除这个lock文件,我们在mysql服务器、zookeeper/kafka 等系统中都能看到lock文件的存在。

public class PreventDuplicated {
    
    
    private final static String LOCK_PATH = "d://lock//";

    private final static String LOCK_FILE = "mysql.lock";

    private static  File lockFile = new File(LOCK_PATH,LOCK_FILE);

    public static void main( String[] args ) throws IOException {
    
    
        /**
         * 1、注入Hook 线程,在程序退出 时 杉树lock文件
         */
        Runtime.getRuntime().addShutdownHook(new Thread(()->;{
    
    
            System.out.println("The program received kill SIGNAL");
            lockFile.delete();
        }));

        /**
         * 2.检查 是否存在.lock文件
         */
        checkRunning();

        for(;;){
    
    
            try {
    
    
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    private static  void checkRunning() throws IOException{
    
    
        if(lockFile.exists()){
    
    
            throw  new RuntimeException("The program already running .");
        }
        lockFile.createNewFile();
    }

}

3、Hook线程使用应用场景

(1) Hook线程只有在收到退出信号的时候会被执行,如果在kill的时候使用了参数-9, 那么Hook线程不会得到执行,进程将会立即退出,因此.lock文件将得不到清理。

(2) Hook线程中也可以执行一些资源释放的工作,比如关闭文件句柄、socket链接、数据库connection等。

(3) 尽量不要再Hook线程中执行一些耗时长的操作,因为其会导致程序迟迟不会退出。

4、怎样获取线程运行时异常?

(1) 在Thread类中,关于处理运行时异常API总共有四个

  • setUncaughtExceptionHandler(UncaughtExceptionHandler eh) :为某个特定线程指定UncaughtExceptionHandler
  • setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) : 设置全局的UncaughtExceptionHandler
  • UncaughtExceptionHandler getUncaughtExceptionHandler() : 获取特定线程的UncaughtExceptionHandler
  • UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(): 获取去全局的UncaughtExceptionHandler

UncaughtExceptionHandler介绍

线程在执行单元中是不允许抛出checked异常的额,而且线程运行在自己的上下文中,派生它的线程将无法直接获得它运行中出现的以常规信息,对此,Java 为我们提供了一个 UncaughtExceptionHandler 接口,,当线程在运行过程中出现异常时,会回调UncaughtExceptionHandler接口,从而得知是哪个线程在运行时出错,以及出现了什么样的错。


public class CaptureThreadException {
    
    

    public static void main( String[] args ) {
    
    
        Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e)->{
    
    
            System.out.println("ERROR:"+t.getName() +" occur exception");
            e.printStackTrace();
        });
        final Thread thread = new Thread(()->{
    
    
            try {
    
    
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            int i = 1/0;
        },"test-thread");
        thread.start();
    }
}

史上最全的并发编程脑图:https://www.processon.com/view/5d43e6cee4b0e47199351b7f

猜你喜欢

转载自blog.csdn.net/fd2025/article/details/108448050