一:线程运行时异常
1、
由于线程不能抛出可以捕获异常,所以需要线程出现异常时jvm调用dispatchUncaughtException方法回调线程异常处理器处理(如果设置了该线程异常处理就是用设置的,没有就是用父线程组的,不然就使用全局线程处理,再不然就直接打印错误)。
jvm调用dispatchUncaughtException方法链路源码:
private void dispatchUncaughtException(Throwable e) {
//获取相应的异常处理器
getUncaughtExceptionHandler().uncaughtException(this, e);
}
//有设置异常处理器就使用设置的异常处理器,没有就用线程组的
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
//该线程通过setUncaughtExceptionHandler方法设置uncaughtExceptionHandler
return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group;
}
//如下就是线程组的异常处理,先使用父线程组,然后默认全局异常处理,作用打印
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);
}
}
}
2、Thread提供的线程处理异常的方法,如下:
//设置某个线程的unchecked异常回调方法
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
//设置全局的线程unchecked异常回调方法
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
//获取某个线程的异常回调处理方法
public UncaughtExceptionHandler getUncaughtExceptionHandler()
//获取全局异常回调处理方法
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
案例使用:
/**
* 捕获线程运行时异常
*/
public class CaptureThreadException {
public static void main(String[] args){
//设置回调接口
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
System.out.println(t.getName()+" occur exception");
e.printstacktrace();
});
final Thread thread=new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
}
//这里会出现unchecked异常
System.out.println(1/0);
},"Test-Thread");
thread.start();
}
}
输出:
Test-Thread occur exception
java.lang.ArithmeticException: / by zero
at chapter07.CaptureThreadException.lambda$main$1(CaptureThreadException.java:24)
at java.lang.Thread.run(Thread.java:748)
如果注释回调接口,也会抛出运行时异常,因为也父线程组没有设置异常处理,也没有全局默认异常处理。
java.lang.ArithmeticException: / by zero
at chapter07.CaptureThreadException.lambda$main$1(CaptureThreadException.java:24)
at java.lang.Thread.run(Thread.java:748)
一、hook(勾子)程序
jvm没有活跃的非守护线程或者系统中断信号,jvm退出时将会执行多个勾子程序。
应用:zookeeper、kafka、MysqL服务器都有一个.lock文件,用来防止程序重复启动,进程收到中断信号时删除这个文件
public class ExitCaptor {
public static void main(String[] args) {
int i = 0;
//勾子程序,在出现异常或者被kil时调用(不能是kill -9)
Runtime.getRuntime().addShutdownHook(new Thread(
new Runnable() {
@Override
public void run() {
System.out.println("The application will be shutdown, do notifyAndRelease");
notifyAndRelease(); //资源关闭、消息提醒、日志
}
}
));
while (true) {
try {
Thread.sleep(1000);
System.out.println("I am working ........");
} catch (InterruptedException e) {
}
if (++i >20){
throw new RuntimeException("is error .....");
}
}
}
private static void notifyAndRelease() {
System.out.println("doing notifyAndRelease.....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Resource、connnction and file is close.....");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("do notifyAndRelease gone.....");
}
}
}
控制台:
I am working ........
I am working ........
I am working ........
I am working ........
I am working ........
I am working ........
I am working ........
I am working ........
Exception in thread "main" java.lang.RuntimeException: is error .....
at com.zixue.springboot_web02.p2c.ExitCaptor.main(ExitCaptor.java:26)
二、程序kill,做一些保护措施
public class ExitCaptor {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(
new Runnable() {
@Override
public void run() {
System.out.println("The application will be shutdown, do notifyAndRelease");
notifyAndRelease();
}
}
));
while (true) {
try {
Thread.sleep(1000);
System.out.println("I am working ........");
} catch (InterruptedException e) {
}
}
}
private static void notifyAndRelease() {
System.out.println("doing notifyAndRelease.....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Resource、connnction and file is close.....");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("do notifyAndRelease gone.....");
}
}
}
linux显示如下 kill 5664
I am working ........
I am working ........
I am working ........
I am working ........
I am working ........
The application will be shutdown, do notifyAndRelease
doing notifyAndRelease.....
I am working ........
I am working ........
**linux显示如下 kill - 9 5664
I am working ........
I am working ........
I am working ........
I am working ........
I am working ........
已杀死
总结:不建议使用kill -9 杀死application,会无法执行一些勾子程序