在使用线程池的时候,发现除了execute()
方法能够执行任务外,还发现有一个方法submit()
能够执行任务。php
submit()
有3个参数不一的方法,这些方法都是在ExecutorService
接口中声明的,在AbstractExecutorService
中实现,而ThreadPoolExecutor
继承AbstractExecutorService
。java
<T> Future<T> submit(Callable<T> callable);
<T> Future<T> submit(Runnable var1, T result);
Future<?> submit(Runnable runnable);
咱们能够看到submit()
的参数既能够是Runnable
,又能够是Callable
。对于Runnable
咱们是比较熟的,它是线程Thread
所执行的任务,里面有一个run()
方法,是任务的具体执行操做。那么Callable
呢?咱们一块儿看下他们的代码吧。web
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
Runnable
这里就不介绍了,Callable
接口定义了一个call()
方法,返回一个Callable
指定的泛型类,而且call()
调用的时候会抛出异常。经过比较Runnable
和Callable
还看不什么端倪,那么咱们就看看内部实现吧。ruby
submmit()
参数解析这里重点分析submit()
带参数Runnable
和Callable
的方法ide
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
咱们发现2者的实现没有任何的差别,惟一就是submit()
参数不一样。svg
参数传入newTaskFor()
方法,那么能够确定就是在这个方法里作了什么操做。this
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
newTaskFor()
的目的就是建立一个FutureTask
对象,那咱们追踪到FutureTask
的构造方法(FutureTask
很是关键,后面会分析)。spa
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW;
}
public FutureTask(Callable<V> callable) {
if (callable == null)throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
到了这里咱们知道,其实Runnable
会在这里转化成Callable
。咱们来看下Executors.callable()
具体实现。线程
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
private static final class RunnableAdapter<T> implements Callable<T> {
private final Runnable task;
private final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
Executors.callable()
建立了一个RunnableAdapter
对象,RunnableAdapter
实现了Callable
接口,在call()
方法中调用了传入的Runnable
的run()
,而且将传入的result
参数返回。code
也就是说咱们调用submit()
传入的Runnbale
最终会转化成Callable
,而且返回一个result
值(若是咱们传入这个参数则返回这个参数,不传入则返回null)。
到这里咱们讲清楚了submit()
的参数的区别和内部实现,submit()
方法有一个返回值Future
,下面咱们来分析一下返回值Future
。
submit()
的返回值Future
上面分析submit()
源码可知,submit()
返回的是一个RunnableFuture
类对象,真正是经过newTaskFor()
方法返回一个new FutureTask()
对象。因此submit()
返回的真正的对象是FutureTask
对象。
那么FutureTask
是什么,咱们来看下它的类继承关系。
public class FutureTask<V> implements RunnableFuture<V> {
...
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
经过继承关系咱们能够明确的知道其实FutureTask
就是一个Runnable
。而且有本身run()
实现。咱们来看下FutureTask
的run()
是如何实现的。
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
咱们在new FutureTask()
对象的时候,在FutureTask
构造方法中会对state
状态赋值为NEW
,而且传入一个callable
对象。经过FutureTask
的run()
咱们能够知道,其实就经过state
状态判断,调用callable的call()
。(若是传入的参数是Runnable
,Runnable
在RunnableAdapter
类中转化时,在call()
中,其实调用的就是Runnable
的run()
方法)。
因此在submit()
方法中,调用了一个execute(task)
的方法,实际执行的是FutureTask
的run()
,而FutureTask
的run()
调用的是Callable
的call()
方法。
说了这么多,submit()
最后执行的仍是传入的Runnable
的run()
或Callable
的call()
方法。好像没有FutureTask
什么事啊。
其实不是,submit()
返回FutureTask
对象,经过这个FutureTask
对象调用get()
能够返回submit()
方法传入的一个泛型类参数result
对象,若是是Callable
直接经过call()
返回。这个返回值的能够用来校验任务执行是否成功。
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L); //等待任务执行完
return report(s);//将执行的任务结果返回
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
最后是经过outcome
参数将根据任务的状态将结果返回。那么outcome
参数在哪里赋值了?outcome
参数赋值的地方有好2处,一是FutureTask
的set()
,二是FutureTask
的setException()
。
set()
是在FutureTask
的run()
执行完成后,将传入的result
参数赋值给传入给set()
,赋值给outcome
参数。若是run()
报异常了会将Throwable
对象经过setException()
方法传入,赋值给outcome
变量
你们能够返回上面的run()
查看下。
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
protected void setException(Throwable t) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = t;
U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
finishCompletion();
}
}
submit()
使用案例public class Test {
private static final String SUCCESS = "success";
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
System.out.println("------------------任务开始执行---------------------");
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(5000);
System.out.println("submit方法执行任务完成" + " thread name: " + Thread.currentThread().getName());
return SUCCESS;
}
});
try {
String s = future.get();
if (SUCCESS.equals(s)) {
String name = Thread.currentThread().getName();
System.out.println("通过返回值比较,submit方法执行任务成功 thread name: " + name);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("-------------------main thread end---------------------");
}
}
打印结果:
------------------任务开始执行--------------------- call()调用开始: 1496899867882
submit方法执行任务完成: 1496899872897 thread name: pool-1-thread-1
通过返回值比较,submit方法执行任务成功 thread name: main
-------------------main thread end---------------------
主线程会一直阻塞,等待线程池中的任务执行完后,在执行后面的语句。