ThreadPoolExecutor中的submit()方法详细讲解

更新时间:2023-07-22 20:24:10 阅读: 评论:0

ThreadPoolExecutor中的submit()⽅法详细讲解ThreadPoolExecutor中的submit()⽅法详细讲解
在使⽤线程池的时候,发现除了execute()⽅法可以执⾏任务外,还发现有⼀个⽅法submit()可以执⾏任务。
submit()有3个参数不⼀的⽅法,这些⽅法都是在ExecutorService接⼝中声明的,在AbstractExecutorService中实现,⽽ThreadPoolExecutor继承AbstractExecutorService。
<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呢?我们⼀起看下他们的代码吧。
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
Runnable这⾥就不介绍了,Callable接⼝定义了⼀个call()⽅法,返回⼀个Callable指定的泛型类,并且call()调⽤的时候会抛出异常。通过⽐较Runnable和Callable还看不什么端倪,那么我们就看看内部实现吧。
submmit()参数解析
这⾥重点分析submit()带参数Runnable和Callable的⽅法
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()参数不同。
参数传⼊newTaskFor()⽅法,那么可以肯定就是在这个⽅法⾥做了什么操作。
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⾮常关键,后⾯会分析)。
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;
}
public T call() {
task.run();
return result;
}
}
Executors.callable()创建了⼀个RunnableAdapter对象,RunnableAdapter实现了Callable接⼝,在call()⽅法中调⽤了传⼊
的Runnable的run(),并且将传⼊的result参数返回。
也就是说我们调⽤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();
}
nbf通过继承关系我们可以明确的知道其实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 = fal;
tException(ex);
}
look out
if (ran)
t(result);
}
} finally {
asco// runner must be non-null until state is ttled 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()返回。这个返回值的可以⽤来校验任务执⾏是否成功。
FutureTask的get()的实现郑州公务员网络培训学院
public V get() throws InterruptedException, ExecutionException {progress是什么意思
int s = state;
if (s <= COMPLETING)
s = awaitDone(fal, 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();
basis
throw new ExecutionException((Throwable)x);
}
最后是通过outcome参数将根据任务的状态将结果返回。那么outcome参数在哪⾥赋值了?outcome参数赋值的地⽅有好2处,⼀是FutureTask的t(),⼆是FutureTask的tException()。
t()是在FutureTask的run()执⾏完成后,将传⼊的result参数赋值给传⼊给t(),赋值给outcome参数。如果run()报异常了会将Throwable对象通过tException()⽅法传⼊,赋值给outcome变量
⼤家可以返回上⾯的run()查看下。
protected void t(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
protected void tException(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 = wFixedThreadPool(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 = ();
if (SUCCESS.equals(s)) {
String name = Thread.currentThread().getName();
can anybody hear me
System.out.println("经过返回值⽐较,submit⽅法执⾏任务成功    thread name: " + name);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
钢铁侠3影评e.printStackTrace();
}
System.out.println("-------------------main thread end---------------------");
}
}
打印结果:
-badmood
-----------------任务开始执⾏---------------------
call()调⽤开始: 1496899867882
submit⽅法执⾏任务完成: 1496899872897  thread name: pool-1-thread-1
经过返回值⽐较,submit⽅法执⾏任务成功    thread name: main
-------------------main thread end---------------------
主线程会⼀直阻塞,等待线程池中的任务执⾏完后,在执⾏后⾯的语句。

本文发布于:2023-07-22 20:24:10,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/185546.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:参数   任务   对象   返回   实现   赋值
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图