Hook 線程 簡介
Hook線程也叫鉤子線程惠啄,通常我們在運(yùn)行的時候向應(yīng)用程序注入一個或者多個Hook(鉤子)線程慎恒,這樣任内,JVM在退出的時候撵渡,Hook線程將要會啟動
獲取線程運(yùn)行時異常
public void setUncaughtExceptionHandle(UncaughtExceptionHandler er);//為某個特定線程指定UncaughtException
public static void setDefaultUncaughtExceptionHandler(UncaughtException eh);//為當(dāng)前線程設(shè)置全局的UncaughtException
public UncaughtExceptionHandler getUncaughtExceptionHandler();//獲取特定線程的UncaughtExceptionHandler
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler();//獲取全局的UncaughtExceptionHandler死嗦。
方法介紹:
線程在執(zhí)行單元中是不允許拋出checke異常的趋距,而且線程運(yùn)行在自己的上下問環(huán)境中,派生他的線程將無法直接獲取他的異常信息越除。因此我們需要UncaughtExceptionHandler接口节腐,當(dāng)線程在運(yùn)行的過程中出現(xiàn)了異常時,會回調(diào)UncaughtExceptionHandler接口摘盆,從而得知那個線程在運(yùn)行時出錯翼雀。
實(shí)例代碼如下
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
從上述代碼中,可以看出孩擂,UncaughtExceptionHandler 是一個接口狼渊,只有一個抽象方法,該接口會被Thread中的dispatchUncaughtException 方法處理回調(diào)
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
當(dāng)線程在運(yùn)行時出現(xiàn)異常的時候类垦,JVM會調(diào)用dispatchUncaughtException方法狈邑,該接口會講當(dāng)前線程和異常信息傳遞給該接口.。
public class CauptThreadException {
public static void main(String[] args) {
Thread thread = new Thread("CaptureThreadException"){
@Override
public void run() {
int i = 1 / 0;
}
};
thread.setDefaultUncaughtExceptionHandler(new MyCaughtExceptionHandler());
thread.start();
}
}
public class MyCaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName());
e.printStackTrace();
}
}
原理解析
我們可以打開Thread 類蚤认,看下dispatchUncaughtException 方法 調(diào)用了 getUncaughtExceptionHandler() 方法
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
從上述代碼我們可以分析 米苹,首先 獲取當(dāng)前線程中是否有uncaughtExceptionHandler 如果不等于null 則直接返回,否則返回 ThreadGroup砰琢。然后根據(jù)返回的類型 調(diào)用uncaughtException()方法蘸嘶,
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) { //首先判斷當(dāng)前Thread是否有父Group 良瞧,有則調(diào)用父group的方法
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler();//獲取全局的UncaughtException
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) { //如果沒有父ThreadGroup 同時 也沒有全局的uncaughtExceptionHandler 則直接從異常中信息打印到堆棧中
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
Hook線程應(yīng)用場景及其注意事項(xiàng)
1.Hook線程只有在收到退出信號才會被執(zhí)行,如果 在Kill 命令的時候使用了參數(shù) -9 那么hook線程得不到執(zhí)行训唱。進(jìn)程也會被退出莺褒。
2.Hook線程可以做一些資源釋放的工作,比如關(guān)閉文件雪情,釋放鏈接等等遵岩。
3.不要使用Hook線程執(zhí)行一些耗時非常長的工作,因?yàn)槌绦蜻t遲不會退出巡通。