Java线程池execute与submit的联系与区别
先放两张类的继承实现图
在说 submit 与 execute 之前先了解一些类之间的关系



所以 FutureTask 是 Runnable 的子类,并且 FutureTask 有一个私有变量private Callable<V> callable;
前面两点很重要,FutureTask 继承来的 run 方法中是 执行了 private Callable<V> callable 的 call()方法,并且把返回值的引用保存下来。
public void run() {
。。。
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
。。。。
}
if (ran)
set(result);
}
} finally {
。。。
}
}
submit 与 execute的具体实现
execute 是在 Executor 接口中定义,在ThreadPoolExecutor 类中实现。
submit 是在 ExecutorService 接口中定义,在 AbstractExecutorService 抽象类中实现。 并且有三种重载实现:
- Future submit(Callable task);
- Future submit(Runnable task, T result);
- Future<?> submit(Runnable task);
虽然有三种重载实现,但是这些方法的内部实现都是一样的。所以我们以第一种举例:
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
有底向上分析
execute(ftask):ftask 能够作为参数,是因为 RunnableFuture 是 Runnable 的子类(Java多态)
newTaskFor(task):返回的是 FutureTask(RunnableFuture的实现类),真正调用的构造行数:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
总结
在上面我们说了,FutureTask 是Runnable的子类,所以必然是线程类(存在run()方法)。而且 FutureTask 还存在 private Callable<V> callable 。所以,以FutureTask开启线程的时候,在run()方法的内部继续执行 private Callable<V> callable 的 call()方法,并且获取其返回值地址。
还有一点
Future<?> submit(Runnable task):点击去发现Executors.callable(runnable, result)
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
所以,Runnable作为参数,使用这个适配器既可以转化为Callable了。