我们知道线程池通过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 implements RunnableFuture {
/**
* 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 callable;
/** The result to return or exception to throw from get() */
private Object outcome;
public FutureTask(Callable 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 Callable callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter(task, result);
}
/**
* A callable that runs given task and returns given result
*/
static final class RunnableAdapter implements Callable {
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 = CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
通过get()获取结果的过程:
判断任务是否达到最终态。若达到,则根据状态将outcome值区分处理
若未达到
通过LockSupport.parkNanos(futureTask, nanos);挂起当前线程;
futureTask执行到最终态后会执行LockSupport.unpark(thread);重新恢复 因调用get()而挂起的线程
Original: https://www.cnblogs.com/mlwy/p/15448679.html
Author: zy苦行僧
Title: 线程池系列二:一张动图,彻底懂了execute和submit
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/576380/
转载文章受原作者版权保护。转载请注明原作者出处!