线程执行完run方法便可正常退出,若是发生了没有捕获的异常则会异常退出。大多数状况下,因为异常致使的线程退出都不是咱们想要的。因此在编写的代码的时候要尽量的捕获处理能够处理的异常,可是也不能光简单的捕获异常而后什么也不作。下面介绍线程异常的处理办法。
JVM为咱们提供了线程的未捕获异常处理机制,经过Thread的setUncaughtExceptionHandler方法:
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
能够设置当前线程的未捕获异常处理器。以下面的例子就经过设置uncaughtExceptionHandler成功捕获到了除0异常:
public static void main(String[] args) throws InterruptedException { Thread t = new Thread(new UncaughtException.Run());
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("uncaughtExceptionHandler catch a Exception---------");
System.out.println(e.getMessage());
}
});
t.start();
Thread.sleep(100);
}
static class Run implements Runnable{br/>@Override
public void run() {
System.out.println("runnable run---------------");
int i = 1/0;
}
}
结果:
runnable run---------------
uncaughtExceptionHandler catch a Exception---------
/ by zero
线程出现未捕获异常后,JVM将调用Thread中的dispatchUncaughtException方法把异常传递给线程的未捕获异常处理器。
/**html
intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
方法的描述已经清楚地说明了这个方法只是提供给JVM调用的,getUncaughtExceptionHandler方法并无简单返回设置好的uncaughtExceptionHandler:
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
可见,若是没有设置uncaughtExceptionHandler,将使用线程所在的线程组来处理这个未捕获异常。线程组ThreadGroup实现了UncaughtExceptionHandler,因此能够用来处理未捕获异常。ThreadGroup类定义:
class ThreadGroup implements Thread.UncaughtExceptionHandler
ThreadGroup实现的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 \""app
t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
默认状况下,线程组处理未捕获异常的逻辑是,首先将异常消息通知给父线程组,而后尝试利用一个默认的defaultUncaughtExceptionHandler来处理异常,若是没有默认的异常处理器则将错误信息输出到System.err。也就是JVM提供给咱们亨达返佣www.fx61.com/brokerlist/HantecGlobal.html设置每一个线程的具体的未捕获异常处理器,也提供了设置默认异常处理器的方法。
设置了默认的异常处理器后,系统中全部未直接设置异常处理器的线程将使用这个默认的异常处理器。
public void defaultWay(){
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("I catch a exception from " + Thread.currentThread().getName() + ":" + Thread.currentThread().getThreadGroup().getName());
}
});
ThreadGroup myGroup = new ThreadGroup("myGroup");
new Thread(myGroup, new Runnable() {br/>@Override
public void run() {
int i = 1/0;
}
}, "thread1").start();
new Thread(myGroup, new Runnable() {br/>@Override
public void run() {
int i = 1/0;
}
}, "thread2").start();
}
这段代码建立了两个线程,而且它们都会抛出异常,最终由统一的默认异常处理器来处理。结果:
I catch a exception from thread1:myGroup
I catch a exception from thread2:myGroup
固然,出现上面的结果是由于使用了默认的ThreadGroup,咱们能够破坏它这个机制。若是把上面代码中的ThreadGroup换成下面的BadGroup则状况会发生变化:
class BadGroup extends ThreadGroup{
public BadGroup(String name) {br/>super(name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("I am a bad group and do nothing");
}
}
若是使用了BadGroup得出结果将是打印两条I am a bad group and do nothing。
上面的例子中,不管是ThreadGroup或者BadGroup都主动的给线程设置了线程组,那么若是不给线程设置线程组会怎么样呢?还会正常的使用默认异常处理器吗?这些跟线程组的来源相关,先看一个例子:
public void mainGroup() throws InterruptedException {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("I catch a exception from " + Thread.currentThread().getName() + ":" + Thread.currentThread().getThreadGroup().getName());
}
});
new Thread(new Runnable() {br/>@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " said my thread group is " + Thread.currentThread().getThreadGroup().getName());
new Thread(new Runnable() {br/>@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " said my thread group is " + Thread.currentThread().getThreadGroup().getName());
int i = 1/0;
}
}, "thread2").start();
}
}, "thread1").start();ide
Thread.sleep(10);
}
这个方法中,首先建立启动了一个线程,而后又在这个线程中建立启动了另外一个线程,它们都没有主动设置线程组。然而,它们都是有线程组的,其执行的结果以下:
thread1 said my thread group is main
thread2 said my thread group is main
I catch a exception from thread2:main
虚拟机执行main方法的线程属于一个名字叫作“main”的线程组。在应用程序中,建立一个线程的时候若是没有从新制定线程组,则会继承这个“main”线程组。也就是说全部的线程都会有线程组,即便咱们在构造线程时显示的传入null值的线程组,最终JVM也会为咱们分配到一个线程组。Thread的init方法决定了这个特性:
if (g == null) {
/ Determine if it's an applet or not /
/ If there is a security manager, ask the security manager
what to do. /
if (security != null) {
g = security.getThreadGroup();
}
/ If the security doesn't have a strong opinion of the matter
use the parent thread group. /
if (g == null) {
g = parent.getThreadGroup();
}
}
首先咱们要先定义这个线程异常捕获的处理器
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕获异常处理方法:" + e);
}
}
咱们有三种方式使用该线程异常捕获器:
一、在建立线程的时候进行设置
Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();
二、使用Executors建立线程时,还能够在TreadFactory中设置
ExecutorService exec = Executors.newCachedThreadPool(new ThreadFactory(){br/>@Override
public Thread newThread(Runnable r) {
Thread thread = newThread(r);
thread.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
return thread;
}
});
exec.execute(new ExceptionThread());
三、若是咱们只须要一个线程异常处理器处理线程的异常,那么咱们能够设置一个默认的线程异常捕获器,当线程出现异常时,
若是咱们没有指定线程的异常捕获器,并且线程组也没有设置(线程组不用考虑,由于这是一个不成功的尝试),那么就会使用
默认的线程异常捕获器。
// 设置默认的线程异常捕获处理器
Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
经过以上方法就能够捕获并处理线程的异常了。this