Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。
Runnable
其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 :
- publicinterfaceRunnable{
- /**
- *Whenanobjectimplementinginterface<code>Runnable</code>isused
- *tocreateathread,startingthethreadcausestheobject's
- *<code>run</code>methodtobecalledinthatseparatelyexecuting
- *thread.
- *<p>
- *
- *@seejava.lang.Thread#run()
- */
- publicabstractvoidrun();
- }
Callable
Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 :
- publicinterfaceCallable<V>{
- /**
- *Computesaresult,orthrowsanexceptionifunabletodoso.
- *
- *@returncomputedresult
- *@throwsExceptionifunabletocomputearesult
- */
- Vcall()throwsException;
- }
Future
Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下 :
- /**
- *@seeFutureTask
- *@seeExecutor
- *@since1.5
- *@authorDougLea
- *@param<V>TheresulttypereturnedbythisFuture's<tt>get</tt>method
- */
- publicinterfaceFuture<V>{
- /**
- *Attemptstocancelexecutionofthistask.Thisattemptwill
- *failifthetaskhasalreadycompleted,hasalreadybeencancelled,
- *orcouldnotbecancelledforsomeotherreason.Ifsuccessful,
- *andthistaskhasnotstartedwhen<tt>cancel</tt>iscalled,
- *thistaskshouldneverrun.Ifthetaskhasalreadystarted,
- *thenthe<tt>mayInterruptIfRunning</tt>parameterdetermines
- *whetherthethreadexecutingthistaskshouldbeinterruptedin
- *anattempttostopthetask.*
- */
- booleancancel(booleanmayInterruptIfRunning);
- /**
- *Returns<tt>true</tt>ifthistaskwascancelledbeforeitcompleted
- *normally.
- */
- booleanisCancelled();
- /**
- *Returns<tt>true</tt>ifthistaskcompleted.
- *
- */
- booleanisDone();
- /**
- *Waitsifnecessaryforthecomputationtocomplete,andthen
- *retrievesitsresult.
- *
- *@returnthecomputedresult
- */
- Vget()throwsInterruptedException,ExecutionException;
- /**
- *Waitsifnecessaryforatmostthegiventimeforthecomputation
- *tocomplete,andthenretrievesitsresult,ifavailable.
- *
- *@paramtimeoutthemaximumtimetowait
- *@paramunitthetimeunitofthetimeoutargument
- *@returnthecomputedresult
- */
- Vget(longtimeout,TimeUnitunit)
- throwsInterruptedException,ExecutionException,TimeoutException;
- }
FutureTask
FutureTask则是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,
- publicclassFutureTask<V>implementsRunnableFuture<V>
- publicinterfaceRunnableFuture<V>extendsRunnable,Future<V>{
- /**
- *SetsthisFuturetotheresultofitscomputation
- *unlessithasbeencancelled.
- */
- voidrun();
- }
另外它还可以包装Runnable和Callable<V>, 由构造函数注入依赖。
- publicFutureTask(Callable<V>callable){
- if(callable==null)
- thrownewNullPointerException();
- this.callable=callable;
- this.state=NEW;//ensurevisibilityofcallable
- }
- publicFutureTask(Runnablerunnable,Vresult){
- this.callable=Executors.callable(runnable,result);
- this.state=NEW;//ensurevisibilityofcallable
- }
- publicstatic<T>Callable<T>callable(Runnabletask,Tresult){
- if(task==null)
- thrownewNullPointerException();
- returnnewRunnableAdapter<T>(task,result);
- }
- /**
- *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.effective.java.concurrent.task;
- importjava.util.concurrent.Callable;
- importjava.util.concurrent.ExecutionException;
- importjava.util.concurrent.ExecutorService;
- importjava.util.concurrent.Executors;
- importjava.util.concurrent.Future;
- importjava.util.concurrent.FutureTask;
- /**
- *
- *@authormrsimple
- *
- */
- publicclassRunnableFutureTask{
- /**
- *ExecutorService
- */
- staticExecutorServicemExecutor=Executors.newSingleThreadExecutor();
- /**
- *
- *@paramargs
- */
- publicstaticvoidmain(String[]args){
- runnableDemo();
- futureDemo();
- }
- /**
- *runnable,无返回值
- */
- staticvoidrunnableDemo(){
- newThread(newRunnable(){
- @Override
- publicvoidrun(){
- System.out.println("runnabledemo:"+fibc(20));
- }
- }).start();
- }
- /**
- *其中Runnable实现的是voidrun()方法,无返回值;Callable实现的是V
- *call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下
- *,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
- */
- staticvoidfutureDemo(){
- try{
- /**
- *提交runnable则没有返回值,future没有数据
- */
- Future<?>result=mExecutor.submit(newRunnable(){
- @Override
- publicvoidrun(){
- fibc(20);
- }
- });
- System.out.println("futureresultfromrunnable:"+result.get());
- /**
- *提交Callable,有返回值,future中能够获取返回值
- */
- Future<Integer>result2=mExecutor.submit(newCallable<Integer>(){
- @Override
- publicIntegercall()throwsException{
- returnfibc(20);
- }
- });
- System.out
- .println("futureresultfromcallable:"+result2.get());
- /**
- *FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
- *另外它还可以包装Runnable(实际上会转换为Callable)和Callable
- *<V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
- *,并且还可以通过vget()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
- */
- FutureTask<Integer>futureTask=newFutureTask<Integer>(
- newCallable<Integer>(){
- @Override
- publicIntegercall()throwsException{
- returnfibc(20);
- }
- });
- //提交futureTask
- mExecutor.submit(futureTask);
- System.out.println("futureresultfromfutureTask:"
- +futureTask.get());
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }catch(ExecutionExceptione){
- e.printStackTrace();
- }
- }
- /**
- *效率底下的斐波那契数列,耗时的操作
- *
- *@paramnum
- *@return
- */
- staticintfibc(intnum){
- if(num==0){
- return0;
- }
- if(num==1){
- return1;
- }
- returnfibc(num-1)+fibc(num-2);
- }
- }
输出结果
Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。
Runnable
其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 :
- publicinterfaceRunnable{
- /**
- *Whenanobjectimplementinginterface<code>Runnable</code>isused
- *tocreateathread,startingthethreadcausestheobject's
- *<code>run</code>methodtobecalledinthatseparatelyexecuting
- *thread.
- *<p>
- *
- *@seejava.lang.Thread#run()
- */
- publicabstractvoidrun();
- }
Callable
Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 :
- publicinterfaceCallable<V>{
- /**
- *Computesaresult,orthrowsanexceptionifunabletodoso.
- *
- *@returncomputedresult
- *@throwsExceptionifunabletocomputearesult
- */
- Vcall()throwsException;
- }
Future
Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下 :
- /**
- *@seeFutureTask
- *@seeExecutor
- *@since1.5
- *@authorDougLea
- *@param<V>TheresulttypereturnedbythisFuture's<tt>get</tt>method
- */
- publicinterfaceFuture<V>{
- /**
- *Attemptstocancelexecutionofthistask.Thisattemptwill
- *failifthetaskhasalreadycompleted,hasalreadybeencancelled,
- *orcouldnotbecancelledforsomeotherreason.Ifsuccessful,
- *andthistaskhasnotstartedwhen<tt>cancel</tt>iscalled,
- *thistaskshouldneverrun.Ifthetaskhasalreadystarted,
- *thenthe<tt>mayInterruptIfRunning</tt>parameterdetermines
- *whetherthethreadexecutingthistaskshouldbeinterruptedin
- *anattempttostopthetask.*
- */
- booleancancel(booleanmayInterruptIfRunning);
- /**
- *Returns<tt>true</tt>ifthistaskwascancelledbeforeitcompleted
- *normally.
- */
- booleanisCancelled();
- /**
- *Returns<tt>true</tt>ifthistaskcompleted.
- *
- */
- booleanisDone();
- /**
- *Waitsifnecessaryforthecomputationtocomplete,andthen
- *retrievesitsresult.
- *
- *@returnthecomputedresult
- */
- Vget()throwsInterruptedException,ExecutionException;
- /**
- *Waitsifnecessaryforatmostthegiventimeforthecomputation
- *tocomplete,andthenretrievesitsresult,ifavailable.
- *
- *@paramtimeoutthemaximumtimetowait
- *@paramunitthetimeunitofthetimeoutargument
- *@returnthecomputedresult
- */
- Vget(longtimeout,TimeUnitunit)
- throwsInterruptedException,ExecutionException,TimeoutException;
- }
FutureTask
FutureTask则是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,
- publicclassFutureTask<V>implementsRunnableFuture<V>
- publicinterfaceRunnableFuture<V>extendsRunnable,Future<V>{
- /**
- *SetsthisFuturetotheresultofitscomputation
- *unlessithasbeencancelled.
- */
- voidrun();
- }
另外它还可以包装Runnable和Callable<V>, 由构造函数注入依赖。
- publicFutureTask(Callable<V>callable){
- if(callable==null)
- thrownewNullPointerException();
- this.callable=callable;
- this.state=NEW;//ensurevisibilityofcallable
- }
- publicFutureTask(Runnablerunnable,Vresult){
- this.callable=Executors.callable(runnable,result);
- this.state=NEW;//ensurevisibilityofcallable
- }
- publicstatic<T>Callable<T>callable(Runnabletask,Tresult){
- if(task==null)
- thrownewNullPointerException();
- returnnewRunnableAdapter<T>(task,result);
- }
- /**
- *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.effective.java.concurrent.task;
- importjava.util.concurrent.Callable;
- importjava.util.concurrent.ExecutionException;
- importjava.util.concurrent.ExecutorService;
- importjava.util.concurrent.Executors;
- importjava.util.concurrent.Future;
- importjava.util.concurrent.FutureTask;
- /**
- *
- *@authormrsimple
- *
- */
- publicclassRunnableFutureTask{
- /**
- *ExecutorService
- */
- staticExecutorServicemExecutor=Executors.newSingleThreadExecutor();
- /**
- *
- *@paramargs
- */
- publicstaticvoidmain(String[]args){
- runnableDemo();
- futureDemo();
- }
- /**
- *runnable,无返回值
- */
- staticvoidrunnableDemo(){
- newThread(newRunnable(){
- @Override
- publicvoidrun(){
- System.out.println("runnabledemo:"+fibc(20));
- }
- }).start();
- }
- /**
- *其中Runnable实现的是voidrun()方法,无返回值;Callable实现的是V
- *call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下
- *,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
- */
- staticvoidfutureDemo(){
- try{
- /**
- *提交runnable则没有返回值,future没有数据
- */
- Future<?>result=mExecutor.submit(newRunnable(){
- @Override
- publicvoidrun(){
- fibc(20);
- }
- });
- System.out.println("futureresultfromrunnable:"+result.get());
- /**
- *提交Callable,有返回值,future中能够获取返回值
- */
- Future<Integer>result2=mExecutor.submit(newCallable<Integer>(){
- @Override
- publicIntegercall()throwsException{
- returnfibc(20);
- }
- });
- System.out
- .println("futureresultfromcallable:"+result2.get());
- /**
- *FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
- *另外它还可以包装Runnable(实际上会转换为Callable)和Callable
- *<V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
- *,并且还可以通过vget()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
- */
- FutureTask<Integer>futureTask=newFutureTask<Integer>(
- newCallable<Integer>(){
- @Override
- publicIntegercall()throwsException{
- returnfibc(20);
- }
- });
- //提交futureTask
- mExecutor.submit(futureTask);
- System.out.println("futureresultfromfutureTask:"
- +futureTask.get());
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }catch(ExecutionExceptione){
- e.printStackTrace();
- }
- }
- /**
- *效率底下的斐波那契数列,耗时的操作
- *
- *@paramnum
- *@return
- */
- staticintfibc(intnum){
- if(num==0){
- return0;
- }
- if(num==1){
- return1;
- }
- returnfibc(num-1)+fibc(num-2);
- }
- }
输出结果