Java中的Callable、Future、FutureTask、Runnable的区别与示例

Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。


Runnable

其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicinterfaceRunnable{
  2. /**
  3. *Whenanobjectimplementinginterface<code>Runnable</code>isused
  4. *tocreateathread,startingthethreadcausestheobject's
  5. *<code>run</code>methodtobecalledinthatseparatelyexecuting
  6. *thread.
  7. *<p>
  8. *
  9. *@seejava.lang.Thread#run()
  10. */
  11. publicabstractvoidrun();
  12. }

Callable

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicinterfaceCallable<V>{
  2. /**
  3. *Computesaresult,orthrowsanexceptionifunabletodoso.
  4. *
  5. *@returncomputedresult
  6. *@throwsExceptionifunabletocomputearesult
  7. */
  8. Vcall()throwsException;
  9. }
可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。

Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. /**
  2. *@seeFutureTask
  3. *@seeExecutor
  4. *@since1.5
  5. *@authorDougLea
  6. *@param<V>TheresulttypereturnedbythisFuture's<tt>get</tt>method
  7. */
  8. publicinterfaceFuture<V>{
  9. /**
  10. *Attemptstocancelexecutionofthistask.Thisattemptwill
  11. *failifthetaskhasalreadycompleted,hasalreadybeencancelled,
  12. *orcouldnotbecancelledforsomeotherreason.Ifsuccessful,
  13. *andthistaskhasnotstartedwhen<tt>cancel</tt>iscalled,
  14. *thistaskshouldneverrun.Ifthetaskhasalreadystarted,
  15. *thenthe<tt>mayInterruptIfRunning</tt>parameterdetermines
  16. *whetherthethreadexecutingthistaskshouldbeinterruptedin
  17. *anattempttostopthetask.*
  18. */
  19. booleancancel(booleanmayInterruptIfRunning);
  20. /**
  21. *Returns<tt>true</tt>ifthistaskwascancelledbeforeitcompleted
  22. *normally.
  23. */
  24. booleanisCancelled();
  25. /**
  26. *Returns<tt>true</tt>ifthistaskcompleted.
  27. *
  28. */
  29. booleanisDone();
  30. /**
  31. *Waitsifnecessaryforthecomputationtocomplete,andthen
  32. *retrievesitsresult.
  33. *
  34. *@returnthecomputedresult
  35. */
  36. Vget()throwsInterruptedException,ExecutionException;
  37. /**
  38. *Waitsifnecessaryforatmostthegiventimeforthecomputation
  39. *tocomplete,andthenretrievesitsresult,ifavailable.
  40. *
  41. *@paramtimeoutthemaximumtimetowait
  42. *@paramunitthetimeunitofthetimeoutargument
  43. *@returnthecomputedresult
  44. */
  45. Vget(longtimeout,TimeUnitunit)
  46. throwsInterruptedException,ExecutionException,TimeoutException;
  47. }

FutureTask

FutureTask则是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicclassFutureTask<V>implementsRunnableFuture<V>
RunnableFuture

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicinterfaceRunnableFuture<V>extendsRunnable,Future<V>{
  2. /**
  3. *SetsthisFuturetotheresultofitscomputation
  4. *unlessithasbeencancelled.
  5. */
  6. voidrun();
  7. }

另外它还可以包装Runnable和Callable<V>, 由构造函数注入依赖。

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicFutureTask(Callable<V>callable){
  2. if(callable==null)
  3. thrownewNullPointerException();
  4. this.callable=callable;
  5. this.state=NEW;//ensurevisibilityofcallable
  6. }
  7. publicFutureTask(Runnablerunnable,Vresult){
  8. this.callable=Executors.callable(runnable,result);
  9. this.state=NEW;//ensurevisibilityofcallable
  10. }
可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicstatic<T>Callable<T>callable(Runnabletask,Tresult){
  2. if(task==null)
  3. thrownewNullPointerException();
  4. returnnewRunnableAdapter<T>(task,result);
  5. }
RunnableAdapter适配器

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. /**
  2. *Acallablethatrunsgiventaskandreturnsgivenresult
  3. */
  4. staticfinalclassRunnableAdapter<T>implementsCallable<T>{
  5. finalRunnabletask;
  6. finalTresult;
  7. RunnableAdapter(Runnabletask,Tresult){
  8. this.task=task;
  9. this.result=result;
  10. }
  11. publicTcall(){
  12. task.run();
  13. returnresult;
  14. }
  15. }

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。

并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、Runnable,又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。


简单示例

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. packagecom.effective.java.concurrent.task;
  2. importjava.util.concurrent.Callable;
  3. importjava.util.concurrent.ExecutionException;
  4. importjava.util.concurrent.ExecutorService;
  5. importjava.util.concurrent.Executors;
  6. importjava.util.concurrent.Future;
  7. importjava.util.concurrent.FutureTask;
  8. /**
  9. *
  10. *@authormrsimple
  11. *
  12. */
  13. publicclassRunnableFutureTask{
  14. /**
  15. *ExecutorService
  16. */
  17. staticExecutorServicemExecutor=Executors.newSingleThreadExecutor();
  18. /**
  19. *
  20. *@paramargs
  21. */
  22. publicstaticvoidmain(String[]args){
  23. runnableDemo();
  24. futureDemo();
  25. }
  26. /**
  27. *runnable,无返回值
  28. */
  29. staticvoidrunnableDemo(){
  30. newThread(newRunnable(){
  31. @Override
  32. publicvoidrun(){
  33. System.out.println("runnabledemo:"+fibc(20));
  34. }
  35. }).start();
  36. }
  37. /**
  38. *其中Runnable实现的是voidrun()方法,无返回值;Callable实现的是V
  39. *call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下
  40. *,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
  41. */
  42. staticvoidfutureDemo(){
  43. try{
  44. /**
  45. *提交runnable则没有返回值,future没有数据
  46. */
  47. Future<?>result=mExecutor.submit(newRunnable(){
  48. @Override
  49. publicvoidrun(){
  50. fibc(20);
  51. }
  52. });
  53. System.out.println("futureresultfromrunnable:"+result.get());
  54. /**
  55. *提交Callable,有返回值,future中能够获取返回值
  56. */
  57. Future<Integer>result2=mExecutor.submit(newCallable<Integer>(){
  58. @Override
  59. publicIntegercall()throwsException{
  60. returnfibc(20);
  61. }
  62. });
  63. System.out
  64. .println("futureresultfromcallable:"+result2.get());
  65. /**
  66. *FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
  67. *另外它还可以包装Runnable(实际上会转换为Callable)和Callable
  68. *<V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
  69. *,并且还可以通过vget()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
  70. */
  71. FutureTask<Integer>futureTask=newFutureTask<Integer>(
  72. newCallable<Integer>(){
  73. @Override
  74. publicIntegercall()throwsException{
  75. returnfibc(20);
  76. }
  77. });
  78. //提交futureTask
  79. mExecutor.submit(futureTask);
  80. System.out.println("futureresultfromfutureTask:"
  81. +futureTask.get());
  82. }catch(InterruptedExceptione){
  83. e.printStackTrace();
  84. }catch(ExecutionExceptione){
  85. e.printStackTrace();
  86. }
  87. }
  88. /**
  89. *效率底下的斐波那契数列,耗时的操作
  90. *
  91. *@paramnum
  92. *@return
  93. */
  94. staticintfibc(intnum){
  95. if(num==0){
  96. return0;
  97. }
  98. if(num==1){
  99. return1;
  100. }
  101. returnfibc(num-1)+fibc(num-2);
  102. }
  103. }

输出结果


Java中存在Runnable、Callable、Future、FutureTask这几个与线程相关的类或者接口,在Java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。


Runnable

其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicinterfaceRunnable{
  2. /**
  3. *Whenanobjectimplementinginterface<code>Runnable</code>isused
  4. *tocreateathread,startingthethreadcausestheobject's
  5. *<code>run</code>methodtobecalledinthatseparatelyexecuting
  6. *thread.
  7. *<p>
  8. *
  9. *@seejava.lang.Thread#run()
  10. */
  11. publicabstractvoidrun();
  12. }

Callable

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Callable的声明如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicinterfaceCallable<V>{
  2. /**
  3. *Computesaresult,orthrowsanexceptionifunabletodoso.
  4. *
  5. *@returncomputedresult
  6. *@throwsExceptionifunabletocomputearesult
  7. */
  8. Vcall()throwsException;
  9. }
可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。

Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. /**
  2. *@seeFutureTask
  3. *@seeExecutor
  4. *@since1.5
  5. *@authorDougLea
  6. *@param<V>TheresulttypereturnedbythisFuture's<tt>get</tt>method
  7. */
  8. publicinterfaceFuture<V>{
  9. /**
  10. *Attemptstocancelexecutionofthistask.Thisattemptwill
  11. *failifthetaskhasalreadycompleted,hasalreadybeencancelled,
  12. *orcouldnotbecancelledforsomeotherreason.Ifsuccessful,
  13. *andthistaskhasnotstartedwhen<tt>cancel</tt>iscalled,
  14. *thistaskshouldneverrun.Ifthetaskhasalreadystarted,
  15. *thenthe<tt>mayInterruptIfRunning</tt>parameterdetermines
  16. *whetherthethreadexecutingthistaskshouldbeinterruptedin
  17. *anattempttostopthetask.*
  18. */
  19. booleancancel(booleanmayInterruptIfRunning);
  20. /**
  21. *Returns<tt>true</tt>ifthistaskwascancelledbeforeitcompleted
  22. *normally.
  23. */
  24. booleanisCancelled();
  25. /**
  26. *Returns<tt>true</tt>ifthistaskcompleted.
  27. *
  28. */
  29. booleanisDone();
  30. /**
  31. *Waitsifnecessaryforthecomputationtocomplete,andthen
  32. *retrievesitsresult.
  33. *
  34. *@returnthecomputedresult
  35. */
  36. Vget()throwsInterruptedException,ExecutionException;
  37. /**
  38. *Waitsifnecessaryforatmostthegiventimeforthecomputation
  39. *tocomplete,andthenretrievesitsresult,ifavailable.
  40. *
  41. *@paramtimeoutthemaximumtimetowait
  42. *@paramunitthetimeunitofthetimeoutargument
  43. *@returnthecomputedresult
  44. */
  45. Vget(longtimeout,TimeUnitunit)
  46. throwsInterruptedException,ExecutionException,TimeoutException;
  47. }

FutureTask

FutureTask则是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicclassFutureTask<V>implementsRunnableFuture<V>
RunnableFuture

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicinterfaceRunnableFuture<V>extendsRunnable,Future<V>{
  2. /**
  3. *SetsthisFuturetotheresultofitscomputation
  4. *unlessithasbeencancelled.
  5. */
  6. voidrun();
  7. }

另外它还可以包装Runnable和Callable<V>, 由构造函数注入依赖。

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicFutureTask(Callable<V>callable){
  2. if(callable==null)
  3. thrownewNullPointerException();
  4. this.callable=callable;
  5. this.state=NEW;//ensurevisibilityofcallable
  6. }
  7. publicFutureTask(Runnablerunnable,Vresult){
  8. this.callable=Executors.callable(runnable,result);
  9. this.state=NEW;//ensurevisibilityofcallable
  10. }
可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. publicstatic<T>Callable<T>callable(Runnabletask,Tresult){
  2. if(task==null)
  3. thrownewNullPointerException();
  4. returnnewRunnableAdapter<T>(task,result);
  5. }
RunnableAdapter适配器

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. /**
  2. *Acallablethatrunsgiventaskandreturnsgivenresult
  3. */
  4. staticfinalclassRunnableAdapter<T>implementsCallable<T>{
  5. finalRunnabletask;
  6. finalTresult;
  7. RunnableAdapter(Runnabletask,Tresult){
  8. this.task=task;
  9. this.result=result;
  10. }
  11. publicTcall(){
  12. task.run();
  13. returnresult;
  14. }
  15. }

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。

并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、Runnable,又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。


简单示例

[java] view plain copy
在CODE上查看代码片 派生到我的代码片
  1. packagecom.effective.java.concurrent.task;
  2. importjava.util.concurrent.Callable;
  3. importjava.util.concurrent.ExecutionException;
  4. importjava.util.concurrent.ExecutorService;
  5. importjava.util.concurrent.Executors;
  6. importjava.util.concurrent.Future;
  7. importjava.util.concurrent.FutureTask;
  8. /**
  9. *
  10. *@authormrsimple
  11. *
  12. */
  13. publicclassRunnableFutureTask{
  14. /**
  15. *ExecutorService
  16. */
  17. staticExecutorServicemExecutor=Executors.newSingleThreadExecutor();
  18. /**
  19. *
  20. *@paramargs
  21. */
  22. publicstaticvoidmain(String[]args){
  23. runnableDemo();
  24. futureDemo();
  25. }
  26. /**
  27. *runnable,无返回值
  28. */
  29. staticvoidrunnableDemo(){
  30. newThread(newRunnable(){
  31. @Override
  32. publicvoidrun(){
  33. System.out.println("runnabledemo:"+fibc(20));
  34. }
  35. }).start();
  36. }
  37. /**
  38. *其中Runnable实现的是voidrun()方法,无返回值;Callable实现的是V
  39. *call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下
  40. *,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
  41. */
  42. staticvoidfutureDemo(){
  43. try{
  44. /**
  45. *提交runnable则没有返回值,future没有数据
  46. */
  47. Future<?>result=mExecutor.submit(newRunnable(){
  48. @Override
  49. publicvoidrun(){
  50. fibc(20);
  51. }
  52. });
  53. System.out.println("futureresultfromrunnable:"+result.get());
  54. /**
  55. *提交Callable,有返回值,future中能够获取返回值
  56. */
  57. Future<Integer>result2=mExecutor.submit(newCallable<Integer>(){
  58. @Override
  59. publicIntegercall()throwsException{
  60. returnfibc(20);
  61. }
  62. });
  63. System.out
  64. .println("futureresultfromcallable:"+result2.get());
  65. /**
  66. *FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
  67. *另外它还可以包装Runnable(实际上会转换为Callable)和Callable
  68. *<V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
  69. *,并且还可以通过vget()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
  70. */
  71. FutureTask<Integer>futureTask=newFutureTask<Integer>(
  72. newCallable<Integer>(){
  73. @Override
  74. publicIntegercall()throwsException{
  75. returnfibc(20);
  76. }
  77. });
  78. //提交futureTask
  79. mExecutor.submit(futureTask);
  80. System.out.println("futureresultfromfutureTask:"
  81. +futureTask.get());
  82. }catch(InterruptedExceptione){
  83. e.printStackTrace();
  84. }catch(ExecutionExceptione){
  85. e.printStackTrace();
  86. }
  87. }
  88. /**
  89. *效率底下的斐波那契数列,耗时的操作
  90. *
  91. *@paramnum
  92. *@return
  93. */
  94. staticintfibc(intnum){
  95. if(num==0){
  96. return0;
  97. }
  98. if(num==1){
  99. return1;
  100. }
  101. returnfibc(num-1)+fibc(num-2);
  102. }
  103. }

输出结果


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值