线程池系列二:一张动图,彻底懂了execute和submit
我们知道线程池通过execute方法执行提交的Runnable任务,但Runnable只是执行任务,没有返回任何信息。
【线程池原理:线程池原来是个外包公司,打工人我悟了】
若是我们想在异步执行完任务后能够拿到结果。怎么处理呢?
我们可以借助Callable来回去返回结果。线程池为我们提供了另外一种方式执行任务,即submit方法
1、为线程池提交任务
execute方法执行Runnable任务
submit方法执行Runnable或Callable任务,且能获取任务返回结果
2、流程分解
2.1、execute方法执行Runnable任务
execute方法将Runnable任务交付给线程池执行
2.2、submit方法执行Runnable或Callable任务
2.2.1、创建futureTask对象(也是Runnable对象),包含属性Callable和object;将futureTask对象引用传递给外部
public class FutureTask<V> implements RunnableFuture<V> { /** * Possible state transitions: * NEW -> COMPLETING -> NORMAL * NEW -> COMPLETING -> EXCEPTIONAL * NEW -> CANCELLED * NEW -> INTERRUPTING -> INTERRUPTED */ private volatile int state; /** The underlying callable; nulled out after running */ private Callable<V> callable; /** The result to return or exception to throw from get() */ private Object outcome; public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; } }复制代码
FutureTask中的状态属性(state)代表任务执行的进度。当任务执行到最终态时,代表任务执行结束。
后面调用get()方法时,判断到最终态才能获取object的值
2.2.2、若传入Runnable任务,将其转为Callable任务,赋值给Callable;
若传入Callable任务,则直接赋值给Callable
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); } /** * A callable that runs given task and returns given 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; } }复制代码
2.2.3、futureTask作为Runnable,execute方法执行此任务(见2.1)
2.2.4、当执行futureTask时,会调用其run方法执行Callable任务
Callable任务若正常返回结果则赋值给object;
若执行异常,则将异常捕获并赋值给object
2.2.5、外部根据futureTask对象引用,调用get()方法,获取到futureTask中的object;区分是返回结果或异常进行处理
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); }复制代码
通过get()获取结果的过程:
判断任务是否达到最终态。若达到,则根据状态将outcome值区分处理
若未达到
通过LockSupport.parkNanos(futureTask, nanos);挂起当前线程;
futureTask执行到最终态后会执行LockSupport.unpark(thread);重新恢复 因调用get()而挂起的线程
-----The End------
如果这个办法对您有用,或者您希望持续关注,也可以在微信公众号中搜索“码路无涯”**。
作者:zy苦行僧
链接:https://juejin.cn/post/7022171435749605406