使用FutureTask而不是Callable有什么好处?

有两种方法可以提交和轮询任务结果

FutureTask futureTask = new FutureTask(callable); 
  1. 使用CallableFuture组合并在ExecutorService提交。 使用future.get()检索结果。

     Future future = service.submit(callable); 
  2. 使用FutureTask 。 这将包装Callable ,然后使用FutureTask检索结果。

     service.execute(task); 

使用FutureTask不是Callable + Future组合有什么好处?

几乎可以肯定没有。 快速浏览一下AbstractExecutorService GrepCode ,可以看出这些方法中的每一个都是辅助方法,最终会为你将Callable / Runnable包装在Future中。

 protected  RunnableFuture newTaskFor(Runnable runnable, T value) { return new FutureTask(runnable, value); } protected  RunnableFuture newTaskFor(Callable callable) { return new FutureTask(callable); } public Future submit(Runnable task) { // ... RunnableFuture ftask = newTaskFor(task, null); execute(ftask); return ftask; } public  Future submit(Runnable task, T result) { // ... RunnableFuture ftask = newTaskFor(task, result); execute(ftask); return ftask; } public  Future submit(Callable task) { // ... RunnableFuture ftask = newTaskFor(task); execute(ftask); return ftask; } 

使用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 { @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> list = new ArrayList>(); //Create MyCallable instance Callable callable = new MyCallable(); for(int i=0; i< 100; i++){ //submit Callable tasks to be executed by thread pool Future future = executor.submit(callable); //add Future to the list, we can get return value using Future list.add(future); } for(Future 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 { 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 futureTask1 = new FutureTask(callable1); FutureTask futureTask2 = new FutureTask(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 } } } }