2015-06-22 90 views
8

有兩種方法來提交和查詢任務的結果使用FutureTask優於Callable的優點是什麼?

FutureTask futureTask = new FutureTask<String>(callable); 
  1. 使用組合CallableFuture並提交ExecutorService。使用future.get()檢索結果。

    Future future = service.submit(callable); 
    
  2. 使用FutureTask。這將包裝Callable,然後使用FutureTask檢索結果。

    service.execute(task); 
    

什麼是使用FutureTask超過Callable +未來組合的優勢在哪裏?

+0

FutureTask實現Future接口,那麼具體條款中方法之間究竟有什麼區別呢? (即舉例) –

+0

FutureTask task = new FutureTask (可調用); \t \t // Implementation 1 \t \t Future fut = service.submit(callable); \t \t //執行2. \t \t服務。執行(任務);爲什麼我們應該選擇實施1而不是實施2?有沒有優勢? –

+2

不要在評論中發佈你的代碼,更新答案。 –

回答

4

幾乎肯定沒有。 AbstractExecutorServiceGrepCode快速瀏覽顯示這些方法中的每一種都只是幫助方法,最終將Callable/Runnable包裝在Future中。

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { 
    return new FutureTask<T>(runnable, value); 
} 

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { 
    return new FutureTask<T>(callable); 
} 

public Future<?> submit(Runnable task) { 
    // ... 
    RunnableFuture<Object> ftask = newTaskFor(task, null); 
    execute(ftask); 
    return ftask; 
} 

public <T> Future<T> submit(Runnable task, T result) { 
    // ... 
    RunnableFuture<T> ftask = newTaskFor(task, result); 
    execute(ftask); 
    return ftask; 
} 

public <T> Future<T> submit(Callable<T> task) { 
    // ... 
    RunnableFuture<T> ftask = newTaskFor(task); 
    execute(ftask); 
    return ftask; 
} 
4

使用Future可以找出Callable任務的狀態並獲取返回的Object。它提供了get()方法,可以等待Callable完成並返回結果。

Future提供cancel()方法來取消關聯的Callable任務。有一個get()方法的重載版本,我們可以指定等待結果的時間,這有助於避免當前線程被更長時間阻塞。有isDone()和isCancelled()方法來查找關聯Callable任務的當前狀態。

這是Callable任務的一個簡單示例,它返回一秒鐘後執行任務的線程的名稱。我們使用Executor框架並行執行100個任務,並使用Future獲取提交任務的結果。

import java.util.ArrayList; 
    import java.util.Date; 
    import java.util.List; 
    import java.util.concurrent.Callable; 
    import java.util.concurrent.ExecutionException; 
    import java.util.concurrent.ExecutorService; 
    import java.util.concurrent.Executors; 
    import java.util.concurrent.Future; 

    public class MyCallable implements Callable<String> { 

     @Override 
     public String call() throws Exception { 
      Thread.sleep(1000); 
      //return the thread name executing this callable task 
      return Thread.currentThread().getName(); 
     } 

     public static void main(String args[]){ 
      //Get ExecutorService from Executors utility class, thread pool size is 10 
      ExecutorService executor = Executors.newFixedThreadPool(10); 
      //create a list to hold the Future object associated with Callable 
      List<Future<String>> list = new ArrayList<Future<String>>(); 
      //Create MyCallable instance 
      Callable<String> callable = new MyCallable(); 
      for(int i=0; i< 100; i++){ 
       //submit Callable tasks to be executed by thread pool 
       Future<String> future = executor.submit(callable); 
       //add Future to the list, we can get return value using Future 
       list.add(future); 
      } 
      for(Future<String> fut : list){ 
       try { 
        //print the return value of Future, notice the output delay in console 
        // because Future.get() waits for task to get completed 
        System.out.println(new Date()+ "::"+fut.get()); 
       } catch (InterruptedException | ExecutionException e) { 
        e.printStackTrace(); 
       } 
      } 
      //shut down the executor service now 
      executor.shutdown(); 
     } 
    } 

其中FutureTask是Future接口的基礎具體實現,並提供異步處理。它包含啓動和取消任務的方法,以及可以返回FutureTask狀態的方法,包括完成或取消。我們需要一個可調用對象來創建未來任務,然後我們可以使用Java線程池執行器來異步處理這些任務。

讓我們看一個簡單的程序FutureTask的例子。

由於FutureTask需要一個可調用的對象,我們將創建一個簡單的Callable實現。

public class MyCallable implements Callable<String> { 

    private long waitTime; 

    public MyCallable(int timeInMillis){ 
     this.waitTime=timeInMillis; 
    } 
    @Override 
    public String call() throws Exception { 
     Thread.sleep(waitTime); 
     //return the thread name executing this callable task 
     return Thread.currentThread().getName(); 
    } 

} 

    import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.FutureTask; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.TimeoutException; 

public class FutureTaskExample { 

    public static void main(String[] args) { 
     MyCallable callable1 = new MyCallable(1000); 
     MyCallable callable2 = new MyCallable(2000); 

     FutureTask<String> futureTask1 = new FutureTask<String>(callable1); 
     FutureTask<String> futureTask2 = new FutureTask<String>(callable2); 

     ExecutorService executor = Executors.newFixedThreadPool(2); 
     executor.execute(futureTask1); 
     executor.execute(futureTask2); 

     while (true) { 
      try { 
       if(futureTask1.isDone() && futureTask2.isDone()){ 
        System.out.println("Done"); 
        //shut down executor service 
        executor.shutdown(); 
        return; 
       } 

       if(!futureTask1.isDone()){ 
       //wait indefinitely for future task to complete 
       System.out.println("FutureTask1 output="+futureTask1.get()); 
       } 

       System.out.println("Waiting for FutureTask2 to complete"); 
       String s = futureTask2.get(200L, TimeUnit.MILLISECONDS); 
       if(s !=null){ 
        System.out.println("FutureTask2 output="+s); 
       } 
      } catch (InterruptedException | ExecutionException e) { 
       e.printStackTrace(); 
      }catch(TimeoutException e){ 
       //do nothing 
      } 
     } 

    } 

} 
+0

這些僅僅是API差異。在功能上,FutureTask似乎沒有任何優勢。 –

+0

而不是優點,它更多的是與實用和情況要求。如果您想更改其行爲或稍後訪問其Callable,則只需要使用FutureTask,但讓Executor爲您構建FutureTask的一個很好的理由是確保沒有可能的方式將多個引用存在於FutureTask實例中。也就是說,Executor擁有這個實例。大多數時候,我們使用Callable和Future。 – Mudassar

相關問題