2015-06-22 154 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

相关问题