:: Enseignements :: ESIPE :: E4INFO :: 2013-2014 :: Java Réseau I - Concurrence et E/S ::
[LOGO]

TP noté de Concurrence


Le but de ce TP noté est d'écrire quelques classes permettant de vérifier que vous maitrisez les bases des mécanismes de protection de code exécuté de manière concurrente.

Vos sources Java produites pendant le TP devront être placées sous le répertoire EXAM de votre compte ($HOME) (qui est vierge dans l'environnement de TP noté); sinon, elles ne seront pas récupérées.
Vous devez aussi configurer votre Eclipse (eclipse-lambda) pour utiliser la version 8 du JRE (qui est disponible ici /usr/local/apps/java8) et le compilateur pour qu'il utilise la version 1.8.

Tout document papier autre que ce que vous avez imprimé vous-même est proscrit. Vous pouvez consulter la javadoc à travers eclipse ou en lançant la commande jdoc dans un shell. Les seuls documents électroniques autorisés sont les supports de cours à l'url http://igm.univ-mlv.fr/~forax/ens/java-avance/cours/pdf/.

Les exercices 1. et 2. sont complètement indépendants et peuvent être traités dans n'importe quel ordre.

Exercice 1 - Liste à ajout en tête avec conservation du minimum

Considérons la classe ListMin suivante, représentant une liste d'entiers qui doit permettre, outre la création d'une liste contenant un entier, d'ajouter un élément en tête de liste et de récupérer le plus petit élément de la Liste.

Actuellement, cette classe n'est pas thread-safe.

  1. Dans un premier temps, sans se préoccuper de la gestion du maillon contenant la valeur minimum (minNode), modifiez le code pour qu'il soit thread-safe lors de l'ajout des éléments par addFirst() en utilisant les opérations atomiques (sans utiliser de synchronized ni de Lock si vous préférez).
  2. Modifiez ensuite le code de sorte que la modification du maillon contenant la valeur minimum (minNode) soit également thread-safe lors de l'ajout des éléments, toujours en utilisant exclusivement des opérations atomiques.
    On ne cherchera pas à essayer de garantir la cohérence entre l'état de la liste et la valeur du minimum à tout instant, mais plutôt à éviter qu'un maillon ne soit pas pris en compte dans la mise à jour du minimum, i.e., après que toutes les threads aient fini leur travail, le minimum doit effectivement renvoyer la plus petite des valeurs de la liste).

Exercice 2 - Enchères

Le but est d'implanter une classe Auction qui permet de simuler un mécanisme d'enchère. Pour simplifier le problème, une instance de la classe ne pourra gérer qu'une seule enchère; si l'on veut simuler plusieurs enchères consécutives, il faudra créer autant d'objets Auction que d'enchères.
L'idée est que la classe possède deux méthodes auction() et bid(). La méthode auction() prend en paramètre un nombre de millisecondes et attend pendant le temps spécifié. La méthode bid() permet à une thread qui l'exécute de participer à l'enchère en cours (cette méthode peut être appelée par plusieurs threads différentes). Elle est appelée avec un argument qui représente une valeur de pari (ou d'enchère): la thread qui l'exécute est alors bloquée. Lorsque le temps spécifié par l'appel à auction() est terminé, l'ensemble des threads qui sont bloquées par un appel à bid()) sur cette enchère sont libérées, et la plus grande des valeurs de pari soumises est renvoyée par les méthodes bid()).
      public class Auction {
        public void auction(int duration) throws InterruptedException {
          //TODO
        }

        public int bid(int value) throws InterruptedException {
          if (value < 0) {
            throw new IllegalArgumentException("value < 0");
          }
          //TODO
        }
      }
    
  1. Implanter les méthodes auction() et bid(), sachant que si une thread en attente sur une des deux méthodes est interrompue, alors une InterruptedException devra être levée par la méthode.
    Un main de test est disponible ici:
  2. La façon dont InterruptedException est gérée n'est pas satifaisante car
    • Si la thread qui a appelée auction() est interrompue, les threads en attente sur bid() attendent indéfiniment.
    • Si une thread qui a appelé bid() a la meilleure enchère et est interrompue, à la fin de l'enchère, toutes les threads restantes vont penser qu'une autre thread a gagné, alors que celle-ci n'est plus en attente sur bid().
    Pour résoudre ces deux problèmes, l'idée est que dès qu'une des threads est interrompue, qu'elle soit sur auction() ou sur bid(), alors toutes les threads qui participent à l'enchère doivent lever l'exception InterruptedException.
    Recopiez le code dans la classe Auction2 et faites les modifications nécessaires pour implanter ce comportement.
    Un main de test est disponible ici:
  3. Pour finir, on veut faire en sorte qu'une seule thread soit capable d'appeler auction(). Lorsque la méthode auction() a été appelée une fois, toute nouvelle tentative de l'appeler, par cette thread ou par une autre, doit lever une exception IllegalStateException sera levée. De plus, après que l'enchère soit finie, tout appel à bid() (ou à auction()) doit lever l'exception IllegalStateException. Recopiez le code dans la classe Auction3 et faites les modifications nécessaires pour implanter ce comportement.