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); } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!