线程池一类下的主要结构为
Executor//execute(Runnable):用于执行此线程。
ExecutorService// 定义了更丰富的功能,例如关闭线程池,执行线程返回结果等等【submit、invokeAll、invokeAny】
AbstractExecutorService//抽象类,对一些方法提供了默认实现。该类实现了ExecutorService中的一些核心方法。例如submit、invokeAll、invokeAny。
submit(Runnable task):生成一个任务类型和Future接口的RunnableFuture对象,随后再执行execute方法,再返回Future。
这里的execute方法在子类中实现。
submit还可支持Callable。
Callable和Runnable的区别在于Callable带有返回值。即Callable = Runnable+返回值。JAVA提供了一个RunnableAdapter将Runnable换成Callable类型。
AbstractExecutorService有三种submit实现。虽然表面上看上去传参类型均不一致,但是实际上均是传入了Callable类型。传入的Runnable会通过newTaskFor方法将其转换成Callable:
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);//封装成FutureTask对象
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);//
this.state = NEW; // ensure visibility of callable
}
我们可以发现在submit方法中,其3种重载实现实际上均是传入了Callable类型。传入的Runnable会通过newTaskFor的方法将其转成Callable:在newTaskFor方法中,会通过Executors.callable方法,将传入的Runnable和result封装成Callable。这个方法中,将Runnable和Result包装成了一个RunnableAdapter。而这个RunnableAdapter实现了Callable接口,其中call方法便是执行了run方法,再返回result。
而除了submit方法之外,还有invokeAll
invokeAll较简单//大体就是将每个Callable先生成得到一个RunnableFuture。然后再循环execute执行每个任务。随后循环判断每个Future的get方法是否isDone,最后再返回Future的list。这个方法如果存在某一个task没有完成,例如出现异常等等,则会取消任务的execute。//future.cancel(ture)
invokeAny
其难点在于只要一个任务成功就要返回,并且取消其他任务。即重点在于找到第一个执行完毕的任务,使用的是LikedBlockingQueue。在源码中,使用到了一个ExecutorCompletionService用于执行任务,该Service内部封装的是一个Executor和一个LinkedBlockingQueue<Future>。在源码中,会先提交一个任务。随后尝试获取有没有执行结果,如若没有,并且还有任务未执行,则继续提交任务。随后如若没有任务在执行,但是还是没有结果,则退出循环。如若设置了超时,则等待相应时间。然如若未设置超时,且任务均已被提交,则一直等到第一个执行结果出来,如若存在了返回结果,则尝试获取结果,如若失败,则需等待下一个执行结果。
注:以上分析基于JDK8
贴上源码
综上便是AbstractExecutorService的相关方法的实现,接下来是其子类ThreadPoolExecutor。