我们说过,没办法直接在主线程的try-catch中捕获子线程的异常。但是,有的时候子线程中会开启一些IO链接,网络资源等,那么,如何在抛出异常的时候进行处理呢?
有几个方案可以实现:
如果想要在主线程能够捕获子线程的异常,可以考虑使用Callable和Future,它们允许主线程获取子线程的执行结果和异常。这样,主线程可以检查子线程是否抛出了异常,并在必要时处理它。以下是一个示例:
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
// 子线程抛出异常
throw new RuntimeException("子线程异常");
});
try {
Integer result = future.get();
System.out.println("子线程结果: " + result);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
System.out.println("捕获到子线程异常"));
}
executor.shutdown();
}
}
以上代码输出结果:
捕获到子线程异常
即,子线程中抛出的异常,我们在主线程中的catch块中捕获到了。
我们还可以使用UncaughtExceptionHandler
,UncaughtExceptionHandler
是 Java 中的一个接口,用于处理未捕获异常,即那些没有被 try-catch 块捕获的异常。它允许定义自定义异常处理器,以便在线程出现未捕获异常时采取特定的操作。
有了它,我们就可以为线程设置一个自定义的未捕获异常处理器,当线程抛出未捕获异常时,该处理器会被调用,我们可以在其中记录异常信息、执行清理操作等。
以下是一个代码示例:
public class HollisUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程 " + t.getName() + " 抛出未捕获异常:" + e.getMessage());
// 在这里可以执行自定义的异常处理逻辑
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
throw new RuntimeException("这是一个未捕获异常");
});
// 设置自定义的未捕获异常处理器
thread.setUncaughtExceptionHandler(new HollisUncaughtExceptionHandler());
thread.start();
}
}
在这个示例中,我们创建了一个自定义的 HollisUncaughtExceptionHandler ,并将其设置为线程的未捕获异常处理器。当线程执行时抛出未捕获异常,uncaughtException 方法会被调用,然后执行我们在其中实现的处理逻辑。
这样也就间接实现了在主线中捕获到子线程中抛出的异常。
Java 8引入了CompletableFuture,它允许你异步执行任务并处理异常。你可以使用CompletableFuture.supplyAsync()来执行任务,并使用handle()方法捕获异常。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 子线程抛出异常
throw new RuntimeException("子线程异常");
});
future.handle((result, exception) -> {
if (exception != null) {
System.out.println("捕获到子线程异常: " + exception.getMessage());
} else {
System.out.println("子线程结果: " + result);
}
return null;
});