ThreadPoolExecutor中的submit()⽅法详细讲解
ThreadPoolExecutor中的submit()⽅法详细讲解
在使⽤线程池的时候,发现除了execute()⽅法可以执⾏任务外,还发现有⼀个⽅法submit()可以执⾏任务。
submit()有3个参数不⼀的⽅法,这些⽅法都是在ExecutorService接⼝中声明的,在AbstractExecutorService中实现,⽽ThreadPoolExecutor继
承AbstractExecutorService。
我们可以看到submit()的参数既可以是Runnable,⼜可以是Callable。对于Runnable我们是⽐较熟的,它是线程Thread所执⾏的任务,⾥
⾯有⼀个run()⽅法,是任务的具体执⾏操作。那么Callable呢?我们⼀起看下他们的代码吧。
Runnable这⾥就不介绍了,Callable接⼝定义了⼀个call()⽅法,返回⼀个Callable指定的泛型类,并且call()调⽤的时候会抛出异常。通过
⽐较Runnable和Callable还看不什么端倪,那么我们就看看内部实现吧。
submmit()参数解析
这⾥重点分析submit()带参数Runnable和Callable的⽅法
我们发现2者的实现没有任何的差异,唯⼀就是submit()参数不同。
参数传⼊newTaskFor()⽅法,那么可以肯定就是在这个⽅法⾥做了什么操作。
Future<?>submit(Runnablerunnable);
publicinterfaceRunnable{
voidrun();
}
publicinterfaceCallable
Vcall()throwsException;
}
publicFuture<?>submit(Runnabletask){
if(task==null)thrownewNullPointerException();
RunnableFuture
execute(ftask);
returnftask;
}
public
if(task==null)thrownewNullPointerException();
RunnableFuture
execute(ftask);
returnftask;
}
protected
returnnewFutureTask
}
protected
returnnewFutureTask
}
newTaskFor()的⽬的就是创建⼀个FutureTask对象,那我们追踪到FutureTask的构造⽅法(FutureTask⾮常关键,后⾯会分析)。
到了这⾥我们知道,其实Runnable会在这⾥转化成Callable。我们来看下le()具体实现。
le()创建了⼀个RunnableAdapter对象,RunnableAdapter实现了Callable接⼝,在call()⽅法中调⽤了传⼊
的Runnable的run(),并且将传⼊的result参数返回。
也就是说我们调⽤submit()传⼊的Runnbale最终会转化成Callable,并且返回⼀个result值(如果我们传⼊这个参数则返回这个参数,不传⼊
则返回null)。
到这⾥我们讲清楚了submit()的参数的区别和内部实现,submit()⽅法有⼀个返回值Future,下⾯我们来分析⼀下返回值Future。
submit()的返回值Future
上⾯分析submit()源码可知,submit()返回的是⼀个RunnableFuture类对象,真正是通过newTaskFor()⽅法返回⼀个newFutureTask()对象。
所以submit()返回的真正的对象是FutureTask对象。
那么FutureTask是什么,我们来看下它的类继承关系。
通过继承关系我们可以明确的知道其实FutureTask就是⼀个Runnable。并且有⾃⼰run()实现。我们来看下FutureTask的run()是如何实现
的。
publicFutureTask(Runnablerunnable,Vresult){
le=le(runnable,result);
=NEW;
}
publicFutureTask(Callable
if(callable==null)thrownewNullPointerException();
le=callable;
=NEW;
}
publicstatic
if(task==null)
thrownewNullPointerException();
returnnewRunnableAdapter
}
privatestaticfinalclassRunnableAdapter
privatefinalRunnabletask;
privatefinalTresult;
RunnableAdapter(Runnabletask,Tresult){
=task;
=result;
}
publicTcall(){
();
returnresult;
}
}
publicclassFutureTask
...
}
publicinterfaceRunnableFuture
voidrun();
}
我们在newFutureTask()对象的时候,在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()的实现
publicvoidrun(){
if(state!=NEW||
!eAndSwapObject(this,RUNNER,null,tThread()))
return;
try{
Callable
if(c!=null&&state==NEW){
Vresult;
booleanran;
try{
result=();
ran=true;
}catch(Throwableex){
result=null;
ran=fal;
tException(ex);
}
if(ran)
t(result);
}
}finally{
//runnermustbenon-nulluntilstateisttledto
//preventconcurrentcallstorun()
runner=null;
//statemustbere-readafternullingrunnertoprevent
//leakedinterrupts
ints=state;
if(s>=INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
publicVget()throwsInterruptedException,ExecutionException{
ints=state;
if(s<=COMPLETING)
s=awaitDone(fal,0L);//等待任务执⾏完
returnreport(s);//将执⾏的任务结果返回
}
privateVreport(ints)throwsExecutionException{
Objectx=outcome;
if(s==NORMAL)
return(V)x;
if(s>=CANCELLED)
thrownewCancellationException();
thrownewExecutionException((Throwable)x);
}
最后是通过outcome参数将根据任务的状态将结果返回。那么outcome参数在哪⾥赋值了?outcome参数赋值的地⽅有好2处,⼀
是FutureTask的t(),⼆是FutureTask的tException()。
t()是在FutureTask的run()执⾏完成后,将传⼊的result参数赋值给传⼊给t(),赋值给outcome参数。如果run()报异常了会
将Throwable对象通过tException()⽅法传⼊,赋值给outcome变量
⼤家可以返回上⾯的run()查看下。
submit()使⽤案例
打印结果:
protectedvoidt(Vv){
if(eAndSwapInt(this,STATE,NEW,COMPLETING)){
outcome=v;
eredInt(this,STATE,NORMAL);//finalstate
finishCompletion();
}
}
protectedvoidtException(Throwablet){
if(eAndSwapInt(this,STATE,NEW,COMPLETING)){
outcome=t;
eredInt(this,STATE,EXCEPTIONAL);//finalstate
finishCompletion();
}
}
publicclassTest{
privatestaticfinalStringSUCCESS="success";
publicstaticvoidmain(String[]args){
ExecutorServiceexecutorService=edThreadPool(3);
n("------------------任务开始执⾏---------------------");
Future
@Override
publicStringcall()throwsException{
(5000);
n("submit⽅法执⾏任务完成"+"threadname:"+tThread().getName());
returnSUCCESS;
}
});
try{
Strings=();
if((s)){
Stringname=tThread().getName();
n("经过返回值⽐较,submit⽅法执⾏任务成功threadname:"+name);
}
}catch(InterruptedExceptione){
tackTrace();
}catch(ExecutionExceptione){
tackTrace();
}
n("-------------------mainthreadend---------------------");
}
}
主线程会⼀直阻塞,等待线程池中的任务执⾏完后,在执⾏后⾯的语句。
------------------任务开始执⾏---------------------
call()调⽤开始:82
submit⽅法执⾏任务完成:97threadname:pool-1-thread-1
经过返回值⽐较,submit⽅法执⾏任务成功threadname:main
-------------------mainthreadend---------------------
本文发布于:2022-12-31 22:48:49,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/68311.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |