不能 ,如果要捕获异常怎么处理。我们要实现UncaughtExceptionHandler这个接口来捕获抛出的异常。
由于Java线程的本质特征,当抛出异常的时候就终止了如果再进行catch,都不在一个线程里面,所以无法捕捉到异常。
Java线程中,要在run()方法中把一切的异常都处理掉,可以使用try-catch块。不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个线程中逃逸的异常的。异常一旦抛出了,那么这个线程就会停止运行,但是不会影响主线程和其它的线程。因为主线程和其它的线程都不知道它抛出了异常。
先给出一个例子,线程在run()方法中抛出异常,看main函数能不能catch到。
先试试 能不能捕获异常
如果下代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DemoCatchException implements Runnable{
@Override
public void run() {
System.out.println(“准备抛出异常”);
throw new RuntimeException();
}public static void main(String[] args) {
Thread thread = new Thread(new DemoCatchException());
ExecutorService eService= Executors.newCachedThreadPool();
eService.execute(thread);
}}
打印结果如下:
准备抛出异常
Exception in thread “pool-1-thread-1” java.lang.RuntimeException
at com.thread.catchexception.DemoCatchException.run(DemoCatchException.java:12)
at java.lang.Thread.run(Thread.java:745)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
从结果来看明显是没有catch到异常,难道是因为我们没有再main函数里面用try catch块包围起来?接下来再做测试:
将代码修改下:
public class DemoCatchException implements Runnable{
@Override
public void run() {
System.out.println(“准备抛出异常”);
throw new RuntimeException();
}public static void main(String[] args) {
try {
Thread thread = new Thread(new DemoCatchException());
ExecutorService eService= Executors.newCachedThreadPool();
eService.execute(thread);
} catch (Exception e) {
System.out.println("我捕捉到异常了。。。。。");
e.printStackTrace();
}
}}
再看打印结果:
打印出的结果一样没有变化
准备抛出异常
Exception in thread “pool-1-thread-1” java.lang.RuntimeException
at com.thread.catchexception.DemoCatchException.run(DemoCatchException.java:11)
at java.lang.Thread.run(Thread.java:745)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
想想一个线程的抛出异常之后就终止了如果再进行catch,都不在一个线程里面。
为了解决这个问题,这个时候我们得去实现UncaughtExceptionHandler这个接口来捕获抛出的异常。UncaughtExceptionHandler是JDK5中的新接口,允许我们在每个线程上面都附加一个异常处理器,Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕捉的异常而在临近死亡时被调用。为了使用这个异常处理器我们创建一个新的线程工厂ThreadFactory。并在new线程时设置UncaughtExceptionHandler。
1:实现 UncaughtExceptionHandler,抓住抛出异常。
import java.lang.Thread.UncaughtExceptionHandler;
/**实现UncaughtExceptionHandler接口,抓住抛出的异常• Title:MyUncaughtExceptionHandler
• @author lwl
• @date 2018年3月21日下午4:07:18
*/
public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("\n [caugth:] : "+e.toString());
}
}
2:创建 抛出异常的线程类ExceptionThread2
/**
• 这里创建抛出异常的线程类
• Title:ExceptionThread2
• @author lwl
• @date 2018年3月21日下午4:01:08
*/
public class ExceptionThread2 implements Runnable {
@Override
public void run() {
Thread thread =Thread.currentThread();
System.out.println(“运行线程名称 ====”+thread.getName());
System.out.println("Exception "+thread.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
3:创建 抛出异常的线程类ExceptionThread3
/**
• 这里创建抛出异常的线程类
• Title:ExceptionThread3
• @author lwl
• @date 2018年3月21日下午4:04:36
*/
public class ExceptionThread3 implements Runnable {
@Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println(“运行线程名称 ====”+thread.getName());
System.out.println("Exception " + thread.getUncaughtExceptionHandler());
throw new NullPointerException();
}
}
4: 实现ThreadFactory来创建线程,为每一个thread对象都附上一个未捕获异常的处理器
/**
• 解决 线程 异常逃逸问题。(一个线程的抛出异常之后就终止了如果再进行catch,都不在一个线程里面。怎么捕捉异常喃)
•
• 这个时候我们得去实现UncaughtExceptionHandler这个接口来捕获抛出的异常。
• UncaughtExceptionHandler是JDK5中的新接口
• ,允许我们在每个线程上面都附加一个异常处理器,Thread.UncaughtExceptionHandler
• .uncaughtException()方法会在线程因未捕捉的异常而在临近死亡时被调用
• 。为了使用这个异常处理器我们创建一个新的线程工厂ThreadFactory。并在new线程时设置UncaughtExceptionHandler。
•
• 实现ThreadFactory来创建线程,为每一个thread对象都附上一个未捕获异常的处理器
•
•
• Title:HandlerThreadFactory
•
•
• @author lwl
• @date 2018年3月21日下午3:54:04
/
public class HandlerThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
System.out.println(“当前类:”+this+":创建一个新线程");
Thread thread= new Thread®;
System.out.println(“创建线程=”+thread);
//为每一个线程设置异常捕获器
thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = " + thread.getUncaughtExceptionHandler());
return thread;
}
}
5:测试 捕获异常
/*• 测试捕获异常
• Title:CaptureUncaughtException
• @author lwl
• @date 2018年3月21日下午4:09:47
*/
public class CaptureUncaughtException {
public static void main(String[] args) {
ExecutorService service =Executors.newCachedThreadPool(new HandlerThreadFactory());
service.execute(new ExceptionThread2());
service.execute(new ExceptionThread3());
}
}
打印结果如下:
当前类:com.thread.catchexception.HandlerThreadFactory@5bf6b81c:创建一个新线程
创建线程=Thread[Thread-0,5,main]
eh = com.thread.catchexception.MyUncaughtExceptionHandler@665292e6
运行线程名称 ====Thread-0
Exception com.thread.catchexception.MyUncaughtExceptionHandler@665292e6当前类:com.thread.catchexception.HandlerThreadFactory@5bf6b81c:创建一个新线程
创建线程=Thread[Thread-1,5,main]
eh = com.thread.catchexception.MyUncaughtExceptionHandler@71662a95当前类:com.thread.catchexception.HandlerThreadFactory@5bf6b81c:创建一个新线程
捕捉: [caugth:] : java.lang.RuntimeException
创建线程=Thread[Thread-2,5,main]
eh = com.thread.catchexception.MyUncaughtExceptionHandler@6a688d6f
运行线程名称 ==== Thread-2
Exception com.thread.catchexception.MyUncaughtExceptionHandler@6a688d6f当前类:com.thread.catchexception.HandlerThreadFactory@5bf6b81c:创建一个新线程
创建线程=Thread[Thread-3,5,main]
eh = com.thread.catchexception.MyUncaughtExceptionHandler@2ce62a39
捕捉: [caugth:] : java.lang.NullPointerException
从打印来看 现在已经捕获了异常
如果你知道将要在代码中处处使用相同的异常处理器,那么更加简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获异常的处理器。
我们可以按照具体的情况,逐个地设置处理器。但是如果我们知道将要在代码的所有地方都是用相同的异常处理器,那么更简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获异常处理器
这个默认的处理器只有在线程不存在非默认的异常处理器时才会调用。 在运行时,系统会检查线程是否有属于自己的异常处理器,如果发现没有,就去检查相应的线程组是否有专有的异常处理器,如果发现也没有,再调用默认的异常处理器。
public class SettingDefaultHandler {
public static void main(String[] args) {
//设置静态异常处理器
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
ExecutorService executorService= Executors.newCachedThreadPool();
executorService.execute(new ExceptionThread2());
}
}
说明:这个处理器只有在不存在线程专有的未捕获异常的情况下才会被调用。系统会检查线程的专有的版本,如果没有发现,则检查线程组是有有其专有的uncaughtException()方法。如果也没有,在调用defaultUncaughtExcept。
总结:
在 java多线程程序中,所有的线程都不允许 抛出未捕获的异常 checked exception(比如sleep时的InterruptedException),也就是说各个 线程都需要自己把自己的 checked exception 处理掉。这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception 部分)进行了约束,但是线程依然有可能抛出 unchecked exception( 如运行时异常) ,当此类异常抛出时,线程就会终结,对应主线程和其他线程完全不受影响。 且完全感知不到某个线程 抛出的异常(也就是说完全无法catch到这个异常)。