天天看點

(6)Hook線程及捕獲線程執行異常

文章目錄

    • Hook線程
    • 線程運作時異常

Hook線程

JVM

程序退出是由于

JVM

程序中沒有活躍的非守護線程,或者收到了系統中斷信号,向

JVM

程式注入一個

Hook

線程,在

JVM

程序退出的時候,

Hook

線程會啟動執行,通過

Runtime

可以為

JVM

注入多個

Hook

線程。

示例

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

        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.");
        }));
        System.out.println("The program will is stopping.");
    }
           

輸出

The program will is stopping.
the hook thread 1 is running.
the hook thread 2 is running.
the hook thread 1 will exit.
the hook thread 2 will exit.
           

注意事項

  1. Hook

    線程隻有在收到退出信号的時候會被執行,如果在 kill 的時候使用了參數 -9,那麼

    Hook

    線程不會得到執行,程序将會立即退出。
  2. Hook

    線程中也可以執行一些資源釋放的工作。
  3. 盡量不要再

    Hook

    線程中執行一些耗時非常長的操作,因為其會導緻程式遲遲不能退出。

線程運作時異常

API

public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) //某個線程指定 UncaughtExceptionHandler 
public UncaughtExceptionHandler getUncaughtExceptionHandler() //擷取該線程指定的UncaughtExceptionHandler 
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) //設定全局線程 UncaughtExceptionHandler 
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() //擷取全局線程 UncaughtExceptionHandler 
           

UncaughtExceptionHandler

@FunctionalInterface
    public interface UncaughtExceptionHandler {
        /**
         * Method invoked when the given thread terminates due to the
         * given uncaught exception.
         * <p>Any exception thrown by this method will be ignored by the
         * Java Virtual Machine.
         * @param t the thread
         * @param e the exception
         */
        void uncaughtException(Thread t, Throwable e);
    }
           

該接口會被

Thread

中的

dispatchUncaughtException

方法調用。

dispatchUncaughtException

方法隻會被

JVM

調用。

/**
     * Dispatch an uncaught exception to the handler. This method is
     * intended to be called only by the JVM.
     */
    private void dispatchUncaughtException(Throwable e) {
        getUncaughtExceptionHandler().uncaughtException(this, e);
    }
           

getUncaughtExceptionHandler

方法

public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }
           

其中

uncaughtExceptionHandler

變量為該線程指定的

UncaughtExceptionHandler

,即調用

public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)

方法設定。

group

為線程組,其實作了

Thread.UncaughtExceptionHandler

接口。預設的

uncaughtException

方法為:

public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }
           

如果父線程組不為 null ,會一直擷取執行父線程組的

uncaughtException

方法,如果父線程組為 null ,則擷取預設的,如果預設的不為 null,則會執行預設。

繼續閱讀