使用FutureTask而不是Callable有什么好处?
有两种方法可以提交和轮询任务结果
FutureTask futureTask = new FutureTask(callable);
-
使用
Callable
和Future
组合并在ExecutorService
提交。 使用future.get()
检索结果。Future future = service.submit(callable);
-
使用
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
使用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 } } } }