ExecutorService

Avant-propos

Dans ce TP, nous allons reprendre les classes du TP précédent et les réaliser en utilisant différents classes implémentant l'interface ExecutorService.

Exercice 1

Dans cet exercice, on utilise l'API Request.java (et Answer.java) vue au TP précédent.

Écrire la classe CheapestPooled en utilisant un ExecutorService. Pour simplifier le code, on suppose que l'API des requêtes ne lève aucune exception.

Pour rappel, la méthode retrieve() lance un nombre fixé de threads qui tentent d'obtenir le prix d'un item et un autre thread s'ocuppe de calculer le moins cher, s'il existe.

Vous pouvez utiliser executorService.invokeAll(Collection<? extends Callable<T>> tasks).

On veut écrire une classe CheapestPooledWithGlobalTimeout qui, en plus des paramètres de CheapestPooled, prend un paramètre timeoutMilliGlobal. Donc, à la construction, cette classe prend :
  • item le nom de l'objet demandé,
  • poolSize la taille du pool de worker-threads,
  • timeoutMilliPerRequest le timeout en milli-secondes pour chaque Request,
  • timeoutMilliGlobal le timeout en milli-secondes pour l'appel à retrieve.
Les Request sont toujours exécutées avec le timeout timeoutMilliPerRequest, mais votre code devra en plus garantir que l'exécution de retrieve ne prend pas plus de timeoutMilliGlobal millisecondes. La réponse renvoyée par retrieve renverra le prix le moins élevé parmi les réponses obtenues.


Écrire la classe CheapestPooledWithGlobalTimeout en utilisant un ExecutorService.

Pour rappel, la méthode retrieve() lance un nombre fixé de threads qui tentent d'obtenir le prix d'un item et un autre thread s'ocuppe de calculer le moins cher, s'il existe. Votre code doit garantir que l'exécution de retrieve ne prend pas plus de timeoutMilliGlobal millisecondes.

Vous pouvez utiliser executorService.invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit). Cette méthode bloque au plus timeout et annule les tâches qui ne sont pas terminées à ce moment.

En utilisant un ExecutorService, écrire une classe FastestPooled dont la méthode retrieve() lance un nombre fixé de threads qui tentent d'obtenir le prix d'un item et renvoie le premier prix obtenu, s'il existe.

Vous pouvez utiliser T executorService.invokeAny(Collection<? extends Callable<T>> tasks).

Exercice 2

Dans cet exercice, on considère RequestWithCancel.java une variante de l'API Request qui diffère de celle-ci par le fait la méthode request ne prend plus de timeout. La méthode request peut donc bloquer indéfiniment. RequestWithCancel offre une méthode cancel permettant d'interrompre la requête depuis un autre thread. Bien entendu, RequestWithCancel est thread safe. Par exemple :

RequestWithCancel request = new RequestWithCancel("amazon.fr", "pikachu");
new Thread(() -> {
  try {
    System.out.println(request.request());
  } catch (InterruptedException e) {
    throw new AssertionError(e);
  }}).start();
Thread.sleep(5_000);
request.cancel();

En utilisant un ExecutorService, écrire la classe CheapestPooledCancel qui fait la même chose que CheapestPooled mais en utilisant des requêtes qui n'ont pas de timeout.

Vous pouvez utiliser un ScheduledExecutorService pour annuler vos RequestWithCancel.