在Java中,主线程默认情况下不能直接拿到子线程抛出的异常。以下从常规情况和可捕获异常的情况来分析:
常规情况
当子线程抛出异常时,如果子线程内部没有对异常进行处理,该异常会在子线程中传播,直到子线程结束,不会直接被主线程捕获。例如:
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
// 模拟子线程抛出异常
int num = 1 / 0;
});
thread.start();
// 主线程不会捕获到子线程的异常
System.out.println("主线程继续执行");
}
}
异常由子线程抛出。
可捕获异常的情况
- 使用Thread.UncaughtExceptionHandler:可以通过为子线程设置
Thread.UncaughtExceptionHandler
来处理子线程中未捕获的异常,在主线程中进行统一处理。示例如下:
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
int num = 1 / 0;
});
// 设置异常处理器
thread.setUncaughtExceptionHandler((t, e) -> {
// 由子线程回调
System.out.println("子线程出现异常: " + e.getMessage());
});
thread.start();
System.out.println("主线程继续执行");
}
}
- 利用Future和Callable:通过
Future
和Callable
配合,可以在主线程中通过Future
的get
方法获取子线程的执行结果或异常。代码示例如下:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Main {
public static void main(String[] args) {
// 创建Callable任务
Callable<Integer> callable = () -> {
int num = 1 / 0;
return num;
};
// 创建FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
try {
// 获取子线程执行结果,如果有异常会抛出
Integer result = futureTask.get();
System.out.println("结果: " + result);
} catch (InterruptedException | ExecutionException e) {
System.out.println("捕获到子线程异常: " + e.getCause().getMessage());
}
}
}
注意:此种情况,如果没有手动在子线程中捕获异常,也没有在主线程中调用futureTask.get(),那么将不会有任何异常抛出,该异常被吞掉!!!