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

Amr*_*dey 18 java concurrency multithreading future

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

FutureTask futureTask = new FutureTask<String>(callable);
Run Code Online (Sandbox Code Playgroud)
  1. 使用Callable和的组合Future并提交ExecutorService.使用检索结果future.get().

    Future future = service.submit(callable);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用FutureTask.这将使用包装Callable然后检索结果FutureTask.

    service.execute(task);
    
    Run Code Online (Sandbox Code Playgroud)

使用FutureTaskover Callable+ Future组合有什么好处?

Old*_*eon 9

几乎可以肯定没有.在快速浏览GrepCode的的AbstractExecutorService每一种方法显示是简单的辅助方法,最终包裹Callable/ RunnableFuture你的.

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;
}
Run Code Online (Sandbox Code Playgroud)


Mud*_*sar 8

使用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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

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
            }
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 这些只是 API 差异。从功能上来说,FutureTask 似乎没有提供任何优势。 (2认同)