一、结论
- 基本没有区别,在
submit
方法中仍然是调用的execute
方法进行任务的执行或进入等待队列或拒绝。 submit
方法比execute
方法多的只是将提交的任务(不管是runnable类型还是callable类型)包装成RunnableFuture
然后传递给execute
方法执行。- submit方法和execute方法最大的不同点在于submit方法可以获取到任务返回值或任务异常信息,execute方法不能获取任务返回值和异常信息。
RunnableFuture
从名字就可以知道,他既是一个Runnable又是一个Future,所以说submit方法提交的任务被包装成RunnableFuture
后,后面执行任务的时候运行的就是RunnableFuture.run()
方法,所以最根本的区别在RunnableFuture.run()
方法里。所以这里才是重点关注的地方。
二、源码对比
①、execute源码
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 【 1 】、worker数量比核心线程数小,直接创建worker执行任务
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 【 2 】、worker数量超过核心线程数,任务直接进入队列。
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//【 3 】、 如果线程池不是运行状态,或者任务进入队列失败,则尝试创建worker执行任务(即:线程阻塞队列满了但
// 线程池中的线程数没达到最大线程数,则新开启一个线程去执行该任务)。
else if (!addWorker(command, false))
reject(command);
}
②、submit源码
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
// 将提交的runnable任务包装成RunnableFuture
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
// 将提交的runnable任务包装成RunnableFuture
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
// 将提交的callable任务包装成RunnableFuture
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
从上面的源码对比中可以看到,submit
方法比execute
方法多的只是将提交的任务(不管是runnable类型还是callable类型)包装成RunnableFuture
,其核心逻辑还是调用的execute方法执行。
③、RunnableFuture.run方法
可以看到RunnableFuture是一个接口,该接口基继承了Runnable, Future。其实现类主要看FutureTask
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
FutureTask
// 可以看到FutureTask实现了RunnableFuture接口
public class FutureTask<V> implements RunnableFuture<V> {
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// 1、状态检查
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 2、调用包装前的实际方法执行并获取返回值
result = c.call();
ran = true;
} catch (Throwable ex) {
// 3、如果执行失败,则保存异常信息
result = null;
ran = false;
setException(ex);
}
// 4、如果执行成功,则将返回值保存起来
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
}
从FutureTask的源码中可以看出,submit方法将提交的任务包装成RunnableFuture
以后,当该任务被执行的时候实际上执行的是RunnableFuture
的run方法,在这个run方法里调用了原来的任务方法执行,并且获取到返回值并且保存起来。
也就是说submit方法和execute方法最大的不同点在于submit方法可以获取到任务返回值或任务异常信息,execute方法不能获取任务返回值和异常信息。