web-dev-qa-db-fra.com

quel est l'avantage d'utiliser FutureTask par rapport à Callable?

Il existe deux approches pour soumettre et interroger la tâche pour le résultat

FutureTask futureTask = new FutureTask<String>(callable);
  1. Utilisez une combinaison de Callable et Future et soumettez sur ExecutorService. Récupérez le résultat en utilisant future.get().

    Future future = service.submit(callable);
    
  2. Utilisez FutureTask. Cela encapsulera Callable, puis récupérera le résultat à l'aide de FutureTask.

    service.execute(task);
    

Quel est l'avantage d'utiliser FutureTask sur Callable + Future combinaison?

19
Amrish Pandey

Presque certainement pas du tout. Une navigation rapide sur GrepCode du AbstractExecutorService montre que chacune de ces méthodes sont simplement des méthodes auxiliaires qui enveloppent finalement le Callable/Runnable dans un Future pour vous.

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

En utilisant Future, nous pouvons découvrir le statut de la tâche Callable et obtenir l'objet retourné. Il fournit la méthode get () qui peut attendre la fin de Callable, puis retourner le résultat.

Future fournit la méthode cancel () pour annuler la tâche Callable associée. Il existe une version surchargée de la méthode get () où nous pouvons spécifier le temps d'attente du résultat, il est utile d'éviter que le thread actuel ne soit bloqué plus longtemps. Il existe des méthodes isDone () et isCancelled () pour connaître l'état actuel de la tâche Callable associée.

Voici un exemple simple de tâche appelable qui renvoie le nom du thread exécutant la tâche après une seconde. Nous utilisons le framework Executor pour exécuter 100 tâches en parallèle et utilisons Future pour obtenir le résultat des tâches soumises.

    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 est l'implémentation concrète de base de l'interface Future et fournit un traitement asynchrone. Il contient les méthodes pour démarrer et annuler une tâche, ainsi que des méthodes qui peuvent renvoyer l'état de la FutureTask comme si elle était terminée ou annulée. Nous avons besoin d'un objet appelable pour créer une tâche future, puis nous pouvons utiliser Java Thread Pool Executor pour les traiter de manière asynchrone.

Voyons l'exemple de FutureTask avec un programme simple.

Étant donné que FutureTask nécessite un objet appelable, nous allons créer une implémentation Callable simple.

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

    }

}
7
Mudassar