天天看點

Java的Runnable、Callable、Future、FutureTask。

Java中存在Runnable、Callable、Future、FutureTask這幾個與線程相關的類或者接口,在Java中也是比較重要的幾個概念,我們通過下面的簡單示例來了解一下它們的作用于差別。

Runnable

其中Runnable應該是我們最熟悉的接口,它隻有一個run()函數,用于将耗時操作寫在其中,該函數沒有傳回值。然後使用某個線程去執行該runnable即可實作多線程,Thread類在調用start()函數後就是執行的是Runnable的run()函數。Runnable的聲明如下 : 

[java]  view plain  copy

  1. public interface Runnable {  
  2.     public abstract void run();  
  3. }  

Callable

Callable與Runnable的功能大緻相似,Callable中有一個call()函數,但是call()函數有傳回值,而Runnable的run()函數不能将結果傳回給客戶程式。Callable的聲明如下 :

[java]  view plain  copy

  1. public interface Callable<V> {  
  2.     V call() throws Exception;  
  3. }  

可以看到,這是一個泛型接口,call()函數傳回的類型就是客戶程式傳遞進來的V類型。

Future

Executor就是Runnable和Callable的排程容器,Future就是對于具體的Runnable或者Callable任務的執行結果進行

取消、查詢是否完成、擷取結果、設定結果操作。get方法會阻塞,直到任務傳回結果(Future簡介)。Future聲明如下 :

[java]  view plain  copy

  1. public interface Future<V> {  
  2.     boolean cancel(boolean mayInterruptIfRunning);  
  3.     boolean isCancelled();  
  4.     boolean isDone();  
  5.     V get() throws InterruptedException, ExecutionException;  
  6.     V get(long timeout, TimeUnit unit)  
  7.         throws InterruptedException, ExecutionException, TimeoutException;  
  8. }  

FutureTask

FutureTask則是一個RunnableFuture<V>,而RunnableFuture實作了Runnbale又實作了Futrue<V>這兩個接口,

[java]  view plain  copy

  1. public class FutureTask<V> implements RunnableFuture<V>  

RunnableFuture

[java]  view plain  copy

  1. public interface RunnableFuture<V> extends Runnable, Future<V> {  
  2.     void run();  
  3. }  

另外它還可以包裝Runnable和Callable<V>, 由構造函數注入依賴。

[java]  view plain  copy

  1. public FutureTask(Callable<V> callable) {  
  2.     if (callable == null)  
  3.         throw new NullPointerException();  
  4.     this.callable = callable;  
  5.     this.state = NEW;       // ensure visibility of callable  
  6. }  
  7. public FutureTask(Runnable runnable, V result) {  
  8.     this.callable = Executors.callable(runnable, result);  
  9.     this.state = NEW;       // ensure visibility of callable  
  10. }  

可以看到,Runnable注入會被Executors.callable()函數轉換為Callable類型,即FutureTask最終都是執行Callable類型的任務。該适配函數的實作如下 :

[java]  view plain  copy

  1. public static <T> Callable<T> callable(Runnable task, T result) {  
  2.     if (task == null)  
  3.         throw new NullPointerException();  
  4.     return new RunnableAdapter<T>(task, result);  
  5. }  

RunnableAdapter擴充卡

[java]  view plain  copy

  1. static final class RunnableAdapter<T> implements Callable<T> {  
  2.     final Runnable task;  
  3.     final T result;  
  4.     RunnableAdapter(Runnable task, T result) {  
  5.         this.task = task;  
  6.         this.result = result;  
  7.     }  
  8.     public T call() {  
  9.         task.run();  
  10.         return result;  
  11.     }  
  12. }  

由于FutureTask實作了Runnable,是以它既可以通過Thread包裝來直接執行,也可以送出給ExecuteService來執行。

并且還可以直接通過get()函數擷取執行結果,該函數會阻塞,直到結果傳回。是以FutureTask既是Future、

Runnable,又是包裝了Callable( 如果是Runnable最終也會被轉換為Callable ), 它是這兩者的合體。

簡單示例

[java]  view plain  copy

  1.  package com.effective.java.concurrent.task;  
  2. import java.util.concurrent.Callable;  
  3. import java.util.concurrent.ExecutionException;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.Executors;  
  6. import java.util.concurrent.Future;  
  7. import java.util.concurrent.FutureTask;  
  8. public class RunnableFutureTask {  
  9.     static ExecutorService mExecutor = Executors.newSingleThreadExecutor();  
  10.     public static void main(String[] args) {  
  11.         runnableDemo();  
  12.         futureDemo();  
  13.     }  
  14.     static void runnableDemo() {  
  15.         new Thread(new Runnable() {  
  16.             @Override  
  17.             public void run() {  
  18.                 System.out.println("runnable demo : " + fibc(20));  
  19.             }  
  20.         }).start();  
  21.     }  
  22.     static void futureDemo() {  
  23.         try {  
  24.             Future<?> result = mExecutor.submit(new Runnable() {  
  25.                 @Override  
  26.                 public void run() {  
  27.                     fibc(20);  
  28.                 }  
  29.             });  
  30.             System.out.println("future result from runnable : " + result.get());  
  31.             Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() {  
  32.                 @Override  
  33.                 public Integer call() throws Exception {  
  34.                     return fibc(20);  
  35.                 }  
  36.             });  
  37.             System.out  
  38.                     .println("future result from callable : " + result2.get());  
  39.             FutureTask<Integer> futureTask = new FutureTask<Integer>(  
  40.                     new Callable<Integer>() {  
  41.                         @Override  
  42.                         public Integer call() throws Exception {  
  43.                             return fibc(20);  
  44.                         }  
  45.                     });  
  46.             // 送出futureTask  
  47.             mExecutor.submit(futureTask) ;  
  48.             System.out.println("future result from futureTask : "  
  49.                     + futureTask.get());  
  50.         } catch (InterruptedException e) {  
  51.             e.printStackTrace();  
  52.         } catch (ExecutionException e) {  
  53.             e.printStackTrace();  
  54.         }  
  55.     }  
  56.     static int fibc(int num) {  
  57.         if (num == 0) {  
  58.             return 0;  
  59.         }  
  60.         if (num == 1) {  
  61.             return 1;  
  62.         }  
  63.         return fibc(num - 1) + fibc(num - 2);  
  64.     }  
  65. }  

輸出結果

Java的Runnable、Callable、Future、FutureTask。

繼續閱讀