Java中的Runnable,Callable,Future,FutureTask的比较
Java中的Runnable,Callable,Future,FutureTask的比较
Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。
Runnable
其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下:
@FunctionalInterface
publicinterfaceRunnable{
/**
*Whenanobjectimplementinginterface<code>Runnable</code>isused
*tocreateathread,startingthethreadcausestheobject's
*<code>run</code>methodtobecalledinthatseparatelyexecuting
*thread.
*<p>
*Thegeneralcontractofthemethod<code>run</code>isthatitmay
*takeanyactionwhatsoever.
*
*@seejava.lang.Thread#run()
*/
publicabstractvoidrun();
}
Callable
Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下:
@FunctionalInterface
publicinterfaceCallable<V>{
/**
*Computesaresult,orthrowsanexceptionifunabletodoso.
*
*@returncomputedresult
*@throwsExceptionifunabletocomputearesult
*/
Vcall()throwsException;
}
可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。
Future
Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下:
*@seeFutureTask
*@seeExecutor
*@since1.5
*@authorDougLea
*@param<V>TheresulttypereturnedbythisFuture's{@codeget}method
*/
publicinterfaceFuture<V>{
/**
*Attemptstocancelexecutionofthistask.Thisattemptwill
*failifthetaskhasalreadycompleted,hasalreadybeencancelled,
*orcouldnotbecancelledforsomeotherreason.Ifsuccessful,
*andthistaskhasnotstartedwhen{@codecancel}iscalled,
*thistaskshouldneverrun.Ifthetaskhasalreadystarted,
*thenthe{@codemayInterruptIfRunning}parameterdetermines
*whetherthethreadexecutingthistaskshouldbeinterruptedin
*anattempttostopthetask.
*
*<p>Afterthismethodreturns,subsequentcallsto{@link#isDone}will
*alwaysreturn{@codetrue}.Subsequentcallsto{@link#isCancelled}
*willalwaysreturn{@codetrue}ifthismethodreturned{@codetrue}.
*
*@parammayInterruptIfRunning{@codetrue}ifthethreadexecutingthis
*taskshouldbeinterrupted;otherwise,in-progresstasksareallowed
*tocomplete
*@return{@codefalse}ifthetaskcouldnotbecancelled,
*typicallybecauseithasalreadycompletednormally;
*{@codetrue}otherwise
*/
booleancancel(booleanmayInterruptIfRunning);
/**
*Returns{@codetrue}ifthistaskwascancelledbeforeitcompleted
*normally.
*
*@return{@codetrue}ifthistaskwascancelledbeforeitcompleted
*/
booleanisCancelled();
/**
*Returns{@codetrue}ifthistaskcompleted.
*
*Completionmaybeduetonormaltermination,anexception,or
*cancellation--inallofthesecases,thismethodwillreturn
*{@codetrue}.
*
*@return{@codetrue}ifthistaskcompleted
*/
booleanisDone();
/**
*Waitsifnecessaryforthecomputationtocomplete,andthen
*retrievesitsresult.
*
*@returnthecomputedresult
*@throwsCancellationExceptionifthecomputationwascancelled
*@throwsExecutionExceptionifthecomputationthrewan
*exception
*@throwsInterruptedExceptionifthecurrentthreadwasinterrupted
*whilewaiting
*/
Vget()throwsInterruptedException,ExecutionException;
/**
*Waitsifnecessaryforatmostthegiventimeforthecomputation
*tocomplete,andthenretrievesitsresult,ifavailable.
*
*@paramtimeoutthemaximumtimetowait
*@paramunitthetimeunitofthetimeoutargument
*@returnthecomputedresult
*@throwsCancellationExceptionifthecomputationwascancelled
*@throwsExecutionExceptionifthecomputationthrewan
*exception
*@throwsInterruptedExceptionifthecurrentthreadwasinterrupted
*whilewaiting
*@throwsTimeoutExceptionifthewaittimedout
*/
Vget(longtimeout,TimeUnitunit)
throwsInterruptedException,ExecutionException,TimeoutException;
}
FutureTask
FutureTask则是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口:
publicclassFutureTask<V>implementsRunnableFuture<V>{
......
}
RunnableFuture
/**
*A{@linkFuture}thatis{@linkRunnable}.Successfulexecutionof
*the{@coderun}methodcausescompletionofthe{@codeFuture}
*andallowsaccesstoitsresults.
*@seeFutureTask
*@seeExecutor
*@since1.6
*@authorDougLea
*@param<V>TheresulttypereturnedbythisFuture's{@codeget}method
*/
publicinterfaceRunnableFuture<V>extendsRunnable,Future<V>{
/**
*SetsthisFuturetotheresultofitscomputation
*unlessithasbeencancelled.
*/
voidrun();
}
另外FutureTask还可以包装Runnable和Callable<V>,由构造函数注入依赖。
/**
*Createsa{@codeFutureTask}thatwill,uponrunning,executethe
*given{@codeCallable}.
*
*@paramcallablethecallabletask
*@throwsNullPointerExceptionifthecallableisnull
*/
publicFutureTask(Callable<V>callable){
if(callable==null)
thrownewNullPointerException();
this.callable=callable;
this.state=NEW;//ensurevisibilityofcallable
}
/**
*Createsa{@codeFutureTask}thatwill,uponrunning,executethe
*given{@codeRunnable},andarrangethat{@codeget}willreturnthe
*givenresultonsuccessfulcompletion.
*
*@paramrunnabletherunnabletask
*@paramresulttheresulttoreturnonsuccessfulcompletion.If
*youdon'tneedaparticularresult,considerusing
*constructionsoftheform:
*{@codeFuture<?>f=newFutureTask<Void>(runnable,null)}
*@throwsNullPointerExceptioniftherunnableisnull
*/
publicFutureTask(Runnablerunnable,Vresult){
this.callable=Executors.callable(runnable,result);
this.state=NEW;//ensurevisibilityofcallable
}
可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下:
/**
*Returnsa{@linkCallable}objectthat,when
*called,runsthegiventaskandreturnsthegivenresult.This
*canbeusefulwhenapplyingmethodsrequiringa
*{@codeCallable}toanotherwiseresultlessaction.
*@paramtaskthetasktorun
*@paramresulttheresulttoreturn
*@param<T>thetypeoftheresult
*@returnacallableobject
*@throwsNullPointerExceptioniftasknull
*/
publicstatic<T>Callable<T>callable(Runnabletask,Tresult){
if(task==null)
thrownewNullPointerException();
returnnewRunnableAdapter<T>(task,result);
}
RunnableAdapter适配器
/**
*Acallablethatrunsgiventaskandreturnsgivenresult
*/
staticfinalclassRunnableAdapter<T>implementsCallable<T>{
finalRunnabletask;
finalTresult;
RunnableAdapter(Runnabletask,Tresult){
this.task=task;
this.result=result;
}
publicTcall(){
task.run();
returnresult;
}
}
由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。
因此FutureTask既是Future、Runnable,又是包装了Callable(如果是Runnable最终也会被转换为Callable),它是这两者的合体。
完整示例:
packagecom.stay4it.rx;
importjava.util.concurrent.Callable;
importjava.util.concurrent.ExecutionException;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.Future;
importjava.util.concurrent.FutureTask;
publicclassFutureTest{
publicstaticclassTaskimplementsRunnable{
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
System.out.println("run");
}
}
publicstaticclassTask2implementsCallable<Integer>{
@Override
publicIntegercall()throwsException{
System.out.println("call");
returnfibc(30);
}
}
/**
*runnable,无返回值
*/
publicstaticvoidtestRunnable(){
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
Future<String>future=(Future<String>)executorService.submit(newTask());
try{
System.out.println(future.get());
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(ExecutionExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
executorService.shutdown();
}
/**
*Callable,有返回值
*/
publicstaticvoidtestCallable(){
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
Future<Integer>future=(Future<Integer>)executorService.submit(newTask2());
try{
System.out.println(future.get());
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(ExecutionExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
executorService.shutdown();
}
/**
*FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
*另外它还可以包装Runnable(实际上会转换为Callable)和Callable
*<V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
*,并且还可以通过vget()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
*/
publicstaticvoidtestFutureTask(){
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
FutureTask<Integer>futureTask=newFutureTask<Integer>(newTask2());
executorService.submit(futureTask);
try{
System.out.println(futureTask.get());
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(ExecutionExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
executorService.shutdown();
}
/**
*FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
*另外它还可以包装Runnable(实际上会转换为Callable)和Callable
*<V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
*,并且还可以通过vget()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
*/
publicstaticvoidtestFutureTask2(){
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
FutureTask<Integer>futureTask=newFutureTask<Integer>(newRunnable(){
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
System.out.println("testFutureTask2run");
}
},fibc(30));
executorService.submit(futureTask);
try{
System.out.println(futureTask.get());
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(ExecutionExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
executorService.shutdown();
}
publicstaticvoidmain(String[]args){
testCallable();
}
/**
*效率低下的斐波那契数列,耗时的操作
*
*@paramnum
*@return
*/
staticintfibc(intnum){
if(num==0){
return0;
}
if(num==1){
return1;
}
returnfibc(num-1)+fibc(num-2);
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!