java线程池使用Executors.newFixedThreadPool创建,创建后,返回ExecutorService对象,该对象除了调用execute()执行线程以外
还有submit()方法,那这两者之间有何区别?接下来我们通过查看submit的底层实现来深挖两者区别。
ExecutorService的实现类是AbstractExecutorService,submit()有三种参数类型,分别为:
public Future<?> submit(Runnable var1)
public <T> Future<T> submit(Runnable var1, T var2)
public <T> Future<T> submit(Callable<T> var1)
发现上面传参主要是两种,一种是Runnable,一种是Callable,这两个接口有什么区别呢,看下方法的具体实现:
public <T> Future<T> submit(Runnable var1, T var2) {
if (var1 == null) {
throw new NullPointerException();
} else {
RunnableFuture var3 = this.newTaskFor(var1, var2);
this.execute(var3);
return var3;
}
}
public <T> Future<T> submit(Callable<T> var1) {
if (var1 == null) {
throw new NullPointerException();
} else {
RunnableFuture var2 = this.newTaskFor(var1);
this.execute(var2);
return var2;
}
}
两者都调用了newTaskFor()
protected <T> RunnableFuture<T> newTaskFor(Runnable var1, T var2) {
return new FutureTask(var1, var2);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> var1) {
return new FutureTask(var1);
}
方法类生成了FutureTask对象,继续看FutureTask类的两个构造方法:
public FutureTask(Callable<V> var1) {
if (var1 == null) {
throw new NullPointerException();
} else {
this.callable = var1;
this.state = 0;
}
}
public FutureTask(Runnable var1, V var2) {
this.callable = Executors.callable(var1, var2);
this.state = 0;
}
其中传递Callabla参数的方法,直接指定了callable的值,而传递Runnable参数的调用了Executors.callable方法,我们看下这个方法:
public static <T> Callable<T> callable(Runnable var0, T var1) {
if (var0 == null) {
throw new NullPointerException();
} else {
return new Executors.RunnableAdapter(var0, var1);
}
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable var1, T var2) {
this.task = var1;
this.result = var2;
}
public T call() {
this.task.run();
return this.result;
}
}
发现最后底层通过RunnableAdapter,将Runnable转化成了Callable,并且返回了传递的result对象。所以本质上submit()提交的Callable和Runnable如出一辙。都是生成一个FutureTask对象,并且赋值对象中的callable和state属性
我们继续返回到上面的submit()方法,newTaskFor方法调用以后,返回了RunnableFuture接口类型,该接口只有一个run()方法,我们到该接口实现类FutureTask中看下run()方法的实现:
public void run() {
if (this.state == 0 && UNSAFE.compareAndSwapObject(this, runnerOffset, (Object)null, Thread.currentThread())) {
boolean var9 = false;
try {
var9 = true;
Callable var1 = this.callable;
if (var1 != null) {
if (this.state == 0) {
Object var2;
boolean var3;
try {
var2 = var1.call();
var3 = true;
} catch (Throwable var10) {
var2 = null;
var3 = false;
this.setException(var10);
}
if (var3) {
this.set(var2);
var9 = false;
} else {
var9 = false;
}
} else {
var9 = false;
}
} else {
var9 = false;
}
} finally {
if (var9) {
this.runner = null;
int var6 = this.state;
if (var6 >= 5) {
this.handlePossibleCancellationInterrupt(var6);
}
}
}
this.runner = null;
int var12 = this.state;
if (var12 >= 5) {
this.handlePossibleCancellationInterrupt(var12);
}
}
}
本质上是调用了callable的call方法,结合之前的分析,就是如果submit传递的是callable则调用其call()方法,如果传递的是runnable(底层通过RunableAdapter实现了callable),则调用run()方法。
在submit()方法中,生成FutureTask后的下一步就是this.execute()执行,即会执行FutureTask的run方法。
到这里我们基本已经清楚submit执行原理了,那为什么还要返回一个FutureTask类呢,既然已经执行了callable的call或者runnable的run,返回这个类不是多此一举?
因为FutureTask中还有个get()方法:
public V get() throws InterruptedException, ExecutionException {
int var1 = this.state;
if (var1 <= 1) {
var1 = this.awaitDone(false, 0L);
}
return this.report(var1);
}
通过这个方法,我们能获取到线程执行完后,我们先前已经传递进去的泛型,可以用来判断线程是否执行完毕,这一点是execute()方法所不具备的