【每天5分钟,进步一点点】在Java中,当我们需要执行大量异步任务时,通常会利用线程池来管理线程资源,以避免频繁创建和销毁线程带来的开销。线程池提供了两个非常重要的方法来提交任务:execute()
和 submit()
。虽然它们都用于执行任务,但它们之间有一些关键的区别,这些区别在实际应用和面试中都是重点考察的内容。下面,让我们来一探究竟。
execute() 方法
execute()
方法是 Executor
接口中的一个方法,它的定义如下:
void execute(Runnable command);这个方法接受一个 Runnable
类型的任务,然后将它提交给线程池去执行。使用 execute()
方法时,我们无法获取任务执行的结果,也无法处理任务执行过程中可能出现的异常。因此,这个方法通常用于那些不需要返回结果的任务。
使用场景示例:
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.execute(() -> {
System.out.println(\"任务运行中,无法获取返回结果\");
});
executor.shutdown();
在上面的例子中,我们创建了一个固定大小的线程池,并通过 execute()
提交了一个打印任务。
submit() 方法
submit()
方法是 ExecutorService
接口中的一个方法,它的定义如下:
Future<?> submit(Runnable task);
<T> Future<T> submit(Callable<T> task);
submit()
方法不仅可以提交 Runnable
任务,还可以提交 Callable
任务。Callable
与 Runnable
类似,但它可以返回一个结果,并且可以抛出异常。submit()
方法会返回一个 Future
对象,通过这个对象我们可以查询任务的执行情况,例如是否完成、是否取消,以及获取任务执行的结果。
使用场景示例:
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<String> future = executor.submit(() -> {
return \"任务执行结果\";
});
System.out.println(\"任务提交,结果待获取\");
System.out.println(future.get()); // 获取任务的执行结果
executor.shutdown();
在这个例子中,我们提交了一个 Callable
任务,并通过返回的 Future
对象获取了执行结果。
submit与execute的区别
返回值:
submit()
方法返回一个Future
对象,可以用来检查任务是否完成,或者获取执行结果。execute()
方法没有返回值。异常处理:
submit()
方法可以处理任务执行过程中抛出的异常,而execute()
方法无法处理异常,异常将被线程池内部处理。任务类型:
submit()
可以提交Callable
任务,而execute()
只能提交Runnable
任务。结果获取: 使用
submit()
可以通过Future.get()
方法获取任务的执行结果,而execute()
无法获取结果。
常见面试题
问:
submit()
和execute()
方法有什么区别?答:
submit()
提交任务后可以返回一个Future
对象,允许我们查询任务执行状态和获取执行结果。而execute()
方法不提供这些功能,且只能提交Runnable
任务。问:
Future.get()
方法有什么用?答:
Future.get()
方法用于获取由submit()
方法提交的Callable
任务的结果。如果任务尚未完成,调用get()
方法的线程将会等待,直到任务完成。问:
Future
的cancel()
方法如何使用?答:
Future
的cancel()
方法可以用来尝试取消一个正在执行的任务。如果任务已经完成、已经取消,或者由于某些原因不能取消,则调用cancel()
方法会返回false
。问:在实际开发中,应该选择
submit()
还是execute()
?答:如果你需要获取任务的执行结果或处理任务中的异常,应选择
submit()
。如果你执行的任务不需要返回结果,只是简单的运行,那么execute()
是一个更轻量级的选择。问:如果
Callable
任务抛出异常会发生什么?答:如果
Callable
任务抛出异常,异常会被封装在Future.get()
方法抛出的ExecutionException
中。这意味着,即使任务执行过程中出现异常,程序也不会立即终止,而是可以在调用Future.get()
时统一处理异常。
理解 submit()
和 execute()
的区别及其使用场景对于有效利用Java线程池至关重要。在实际开发中,根据任务是否需要返回结果和异常处理的需求来选择合适的方法,可以更好地管理线程资源并提高应用程序的性能和可维护性。同时,在面试中,这些知识点也是面试官经常会问到的。




