java 使用 FutureTask 比 Callable 有什么优势?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30976946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 17:54:54  来源:igfitidea点击:

what is the advantage of using FutureTask over Callable?

javamultithreadingconcurrencyfuture

提问by Amrish Pandey

There are two approaches to submitting and polling task for result

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

FutureTask futureTask = new FutureTask<String>(callable);
  1. Use combination of Callableand Futureand submit on ExecutorService. Retrieve result using future.get().

    Future future = service.submit(callable);
    
  2. Use FutureTask. This will wrap Callableand then retrieve result using FutureTask.

    service.execute(task);
    
  1. 使用CallableandFuture和 submit on 的组合ExecutorService。使用 检索结果future.get()

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

    service.execute(task);
    

What is the advantage of using FutureTaskover Callable+ Future combination ?

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

回答by OldCurmudgeon

Almost certainly none at all. A quick browse on GrepCodeof the AbstractExecutorServiceshows each of these methods are simply helper methods that ultimately wrap the Callable/Runnablein a Futurefor you.

几乎可以肯定没有。快速浏览一下GrepCodeAbstractExecutorService显示,这些方法中的每一个都是简单的辅助方法,最终将Callable/包装Runnable在 aFuture中。

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

回答by Mudassar

Using Future we can find out the status of the Callable task and get the returned Object. It provides get() method that can wait for the Callable to finish and then return the result.

使用 Future 我们可以找出 Callable 任务的状态并获取返回的 Object。它提供了 get() 方法,可以等待 Callable 完成然后返回结果。

Future provides cancel() method to cancel the associated Callable task. There is an overloaded version of get() method where we can specify the time to wait for the result, it's useful to avoid current thread getting blocked for longer time. There are isDone() and isCancelled() methods to find out the current status of associated Callable task.

Future 提供了 cancel() 方法来取消关联的 Callable 任务。有一个 get() 方法的重载版本,我们可以在其中指定等待结果的时间,这有助于避免当前线程被阻塞更长时间。有 isDone() 和 isCancelled() 方法可以找出关联的 Callable 任务的当前状态。

Here is a simple example of Callable task that returns the name of thread executing the task after one second. We are using Executor framework to execute 100 tasks in parallel and use Future to get the result of the submitted tasks.

这是 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();
        }
    }

Where as FutureTask is base concrete implementation of Future interface and provides asynchronous processing. It contains the methods to start and cancel a task and also methods that can return the state of the FutureTask as whether it's completed or cancelled. We need a callable object to create a future task and then we can use Java Thread Pool Executor to process these asynchronously.

其中 FutureTask 是 Future 接口的基本具体实现,并提供异步处理。它包含启动和取消任务的方法以及可以返回 FutureTask 状态的方法,无论它是完成还是取消。我们需要一个可调用的对象来创建未来的任务,然后我们可以使用 Java 线程池执行器来异步处理这些。

Let's see the example of FutureTask with a simple program.

让我们用一个简单的程序来看看 FutureTask 的例子。

Since FutureTask requires a callable object, we will create a simple Callable implementation.

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

    }

}