简介
在线程池的使用中,我们一般用ThreadPoolExecutor
来创建线程池,创建好线程池后会将任务提交给线程池来执行。在提交任务的时候,JDK为我们提供了两种不同的提交方式,分别是submit()
和excute()
,那么它们两者之间有什么不同呢?相互之间有什么关系呢?下面简单的介绍下
方法来源不同
execut()
是在线程池的顶级接口Executor
中定义的,而且只有这一个接口,可见这个方法的重要性。
public interface Executor {
void execute(Runnable command);
}
在ThreadPoolExecutor
类中有它的具体实现。
submit()
是在ExecutorService
接口中定义的,并定义了三种重载方式,具体可以查看JDK文档
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
在AbstractExecutorService
类中有它们的具体实现,而ThreadPoolExecutor
继承了AbstractExecutorService
类,所以也有得到submit方法。
接收的参数不同
根据前面列出来的方法签名,可以知道:
execute()
方法只能接收实现Runnable
接口类型的任务
submit()
方法则既可以接收Runnable
类型的任务,也可以接收Callable
类型的任务。
Runnable和Callable的区别是 前者没有返回值,后者可以有返回值,于是这就又引出了下一个区别
返回值不同
execute()
的返回值是void
,线程提交后不能得到线程的返回值。
submit()
的返回值是Future
,通过Future的get()
方法可以获取到线程执行的返回值,get()
方法是同步的,执行get()方法时,如果线程还没执行完,会同步等待,直到线程执行完成。
虽然
submit()
方法可以提交Runnable
类型的参数,但执行Future方法的get()时,线程执行完会返回null,不会有实际的返回值,这是因为Runable本来就没有返回值
下面是JDK中对submit(Runnable task)方法的描述:
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's {@code get} method will
* return {@code null} upon <em>successful</em> completion.
*/
异常的处理
通过查看任务的方法签名,
submit()
执行Runnable/Callable的任务时,run()/call()方法没显式抛出异常。
execute()
执行Runnable的任务时,run()方法有显式的抛出异常。
通过实验发现,用submit()提交任务,任务内有异常也不会打印异常信息。
用execute()方法执行任务,默认情况下,提交到线程池的任务,如果run()
方法中有异常,会打印异常信息。
当调用Future
的get()
方法时,也能打印出任务执行异常信息。
所以,当用submit()提交线程时,run()
orcall()
方法尽量显式的catch异常,这样才不至于任务提交线程池后丢失异常信息。
测试代码如下:
两个线程:
class TestCallable implements Runnable {
@Override
public void run() {
//try { // 为了防止异常丢失,我们应该显式处理异常
int a = 10 / 0;
//} catch (Exception e) {
//e.printStackTrace();
//}
}
}
class TestCallable implements Callable<Integer> {
@Override
public Integer call() {
// 为了防止异常丢失,我们应该显式处理异常
int a = 10 / 0;
return 1;
}
}
测试主类:
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 在线程的执行方法里如果没有异常处理,以下几个都不会有异常信息打印,只要不调用Future的get方法
// executorService.submit(new TestRunnable());
// executorService.submit(new TestCallable());
// Future<?> future = executorService.submit(new TestRunnable());
// Future<Integer> future1 = executorService.submit(new TestCallable());
// 下面才会打印异常信息
// executorService.execute(new TestRunnable());
Future<Integer> future2 = executorService.submit(new TestCallable());
try {
future2.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
以上就是关于线程池中execute()
和 submit()
的不同介绍,如有错误请大家多多指正。