Java线程池-execute方法和submit方法,异常处理有何不同
目录
Java线程池 execute方法和submit方法,异常处理有何不同?
在 Java 线程池中,
execute
方法和
submit
方法都用于向线程池提交任务,但它们在异常处理方面存在显著差异,下面为你详细介绍。
方法概述
execute
方法 :execute
方法是Executor
接口定义的方法,在ThreadPoolExecutor
类中实现,用于提交一个Runnable
任务到线程池执行。submit
方法 :submit
方法是ExecutorService
接口定义的方法,有多个重载版本,可接受Runnable
或Callable
任务,并且会返回一个Future
对象,用于获取任务的执行结果。
异常处理差异
1. 异常抛出方式
execute
方法- 当使用
execute
方法提交Runnable
任务时,如果任务在执行过程中抛出未捕获的异常,该异常会直接抛给线程池中的工作线程。 - 若没有为线程设置
UncaughtExceptionHandler
,异常会导致工作线程终止,线程池会记录该异常的堆栈信息并打印到控制台。
- 当使用
submit
方法- 当使用
submit
方法提交Runnable
或Callable
任务时,任务执行过程中抛出的异常不会直接抛出,而是被封装在Future
对象中。 - 只有当调用
Future
对象的get
方法时,才会以ExecutionException
的形式抛出,其getCause
方法可获取实际的异常。
- 当使用
2. 异常捕获方式
execute
方法- 若要捕获
execute
方法提交任务的异常,可在Runnable
任务的run
方法中使用try-catch
块捕获异常,或者通过自定义ThreadFactory
为线程设置UncaughtExceptionHandler
来捕获未处理的异常。
- 若要捕获
submit
方法- 对于
submit
方法提交的任务,可通过Future
对象的get
方法捕获异常。在调用get
方法时,使用try-catch
块捕获ExecutionException
,再通过getCause
方法获取实际的异常。
- 对于
示例代码
execute
方法异常处理示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecuteExceptionHandling {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
try {
// 模拟抛出异常的代码
int result = 1 / 0;
} catch (Exception e) {
System.out.println("在任务中捕获到异常: " + e.getMessage());
}
});
executorService.shutdown();
}
}
submit
方法异常处理示例
import java.util.concurrent.*;
public class SubmitExceptionHandling {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> future = executorService.submit(() -> {
// 模拟抛出异常的代码
return 1 / 0;
});
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println("通过 Future 捕获到异常: " + e.getCause().getMessage());
}
executorService.shutdown();
}
}
总结
execute
方法提交的任务抛出异常时,异常会直接影响工作线程,需要在任务内部或通过线程的UncaughtExceptionHandler
进行处理。submit
方法提交的任务抛出异常时,异常会被封装在Future
对象中,需要通过调用Future
的get
方法并捕获ExecutionException
来处理。如果没有手动在子线程中捕获异常,也没有在主线程中调用futureTask.get(),那么异常就相当于被系统吞掉了,这是相当危险的,出了问题无法定位!!!
。