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