Exemple de programme Java FutureTask

Il y a quelque temps, j’ai écrit un article sur les interfaces Java Callable Future que nous pouvons utiliser pour bénéficier du traitement concurrentiel des threads tout en étant capables de renvoyer une valeur au programme appelant. FutureTask est l’implémentation concrète de base de l’interface Future et offre un traitement asynchrone. Il contient des méthodes pour démarrer et annuler une tâche, ainsi que des méthodes qui peuvent renvoyer l’état de la FutureTask, que ce soit terminé ou annulé. Nous avons besoin d’un objet callable 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. Puisque FutureTask nécessite un objet callable, nous allons créer une implémentation Callable simple.

package com.journaldev.threads;

import java.util.concurrent.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);
        // retourne le nom du thread exécutant cette tâche callable
        return Thread.currentThread().getName();
	}

}

Voici un exemple de méthode FutureTask et elle montre les méthodes couramment utilisées de FutureTask.

package com.journaldev.threads;

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");
					// arrêter le service d'exécuteur
					executor.shutdown();
					return;
				}
				
				if(!futureTask1.isDone()){
				// attendre indéfiniment que la tâche future soit terminée
				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){
				// ne rien faire
			}
		}
		
	}

}

Lorsque nous exécutons le programme ci-dessus, vous remarquerez qu’il ne print rien pendant un certain temps parce que la méthode get() de FutureTask attend que la tâche soit terminée avant de renvoyer l’objet de sortie. Il existe aussi une méthode surchargée pour attendre seulement un temps spécifié, que nous utilisons pour futureTask2. Remarquez également l’utilisation de la méthode isDone() pour s’assurer que le programme se termine une fois que toutes les tâches sont exécutées. La sortie du programme ci-dessus sera :

FutureTask1 output=pool-1-thread-1
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
FutureTask2 output=pool-1-thread-2
Done

Il n’y a donc pas vraiment d’avantage à utiliser FutureTask, mais cela peut être pratique lorsque nous voulons remplacer certaines méthodes de l’interface Future sans avoir à implémenter toutes les méthodes de l’interface Future.

Source:
https://www.digitalocean.com/community/tutorials/java-futuretask-example-program