:: Enseignements :: Master :: M1 :: 2021-2022 :: Java Avancé ::
[LOGO]

Producteur / consommateur


Exercice 1 - Producer / Consumer

Essayez de faire cet exercice sans regarder votre cours.

Dans cet exercice, nous cherchons à simuler un environement avec plusieurs producteurs et plusieurs consommateurs. Pour cela, nous utiliserons des threads qui exécuteront périodiquement soit un code qui produit des valeurs soit un code qui consomme ces valeurs.

  1. Rappeler quel problème est résolu par le design pattern Producer/Consumer. Comment fonctionne-t-il?
  2. L'interface de buffer utilisée pour un Producer/Consumer est nommée java.util.concurrent.BlockingQueue en Java.
    Comment s'appellent les méthodes de l'interface BlockingQueue qui permettent, respectivement, de mettre une valeur dans le buffer et d'en retirer une valeur ?
  3. Écrire, dans un main, une thread qui affiche périodiquement (disons toutes les 1 ms) le texte "hello" sur la console.
    Modifier votre code pour avoir deux threads qui affichent périodiquement "hello 0" ou "hello 1" (hello suivi du numéro de thread) respectivement toutes les 1 ms et toutes les 4 ms.
    Note: pas de copier/coller SVP !
  4. Modifier une nouvelle fois le code pour que, en plus d'afficher les messages sur la console, les deux threads les insèrent dans une BlockingQueue.
    Que se passe-t-il si l'implantation de BlockingQueue est une LinkedBlockingQueue ?
    Même question si l'implantation est une ArrayBlockingQueue.
    Que peut-on en conclure ?
  5. Écrire un nouveau code qui permet de retirer et afficher les messages de la BlockingQueue sur la console. Créer 3 threads exécutant ce code respectivement toutes les 2 ms, 3 ms et 5 ms.
    Faites varier le nombre de threads et les temps pour voir ce qu'il se passe.

Exercice 2 - Queue bloquante

Nous allons maintenant ré-implanter (en partie) une file bloquante bornée utilisant un tableau circulaire avec ses deux opérations put et take.
Note: la classe java.util.ArrayDeque implante déjà un buffer circulaire non thread-safe.

  1. Écrire une classe SynchronizedBlockingBuffer utilisant des blocs synchronized qui dans un premier temps, lève une exception
    • dans put si il n'y plus de place (la file est pleine).
    • dans take si il n'y a pas d’élément (la file est vide).
    et possède une taille (strictement positive) donnée à la construction.
    Pour tester, vous pourrez ré-utiliser le code du premier exercice.
  2. Modifiez votre code pour que la méthode put soit bloquante si la file est pleine.
    Attention, penser à réveiller la thread lorsque la file n'est plus pleine.
  3. Modifiez votre code pour que la méthode take soit bloquante si la queue est vide.
  4. Écrire une nouvelle classe LockedBlockingBuffer qui utilise les verrous ré-entrants du package java.util.concurrent.locks.Lock.