Dans cet exercice, on reprend le dernier exercice de la séance précédente. On rappelle qu'on souhaite réaliser une classe RendezVous
thread-safe qui offre un méthode set
permettant de proposer une valeur et une méthode get
qui ''bloque'' jusqu'à ce qu'une valeur ait été proposée et la renvoie lorsque c'est le cas.
Écrire la classe RendezVous
Tester votre classe avec le main ci-dessous. Vous devriez observer avec la commande top que votre programme ne consomme quasiment aucun temps processeur.
public static void main(String[] args) throws InterruptedException { var rdv = new RendezVous<String>(); Thread.ofPlatform().start(() -> { try { Thread.sleep(20_000); rdv.set("Message"); } catch (InterruptedException e) { throw new AssertionError(e); } }); System.out.println(rdv.get()); }
Comparer le résultat de la commande top avec le même main
mais en utilisant la classe RendezVous
de la semaine dernière qui fait de l'attente active.
Dans cet exercice, on veut créer une file d'attente thread-safe.
Dans un premier temps, on cherche a réaliser une file
d'attente thread-safe non-bornée que nous appellerons UnboundedSafeQueue<V>
. Cette classe offrira deux méthodes :
add(V value)
qui ajoute un élément à la fin de la file,V take()
qui retire le premier élément de la file et le renvoie. Si la file est vide, la méthode doit attendre jusqu'à ce qu'un élément soit ajouté..Écrire la classe UnboundedSafeQueue<V>
.
Écrire un main
qui démarre 3 threads qui, toutes les 2 secondes, vont ajouter leur nom (utiliser getName()
) dans une UnboundedSafeQueue
. Le main
effectuera une boucle qui récupère en permanence le premier élément de la UnboundedSafeQueue
et l'affiche.
Nous voulons maintenant réaliser une file d'attente thread-safe de taille bornée BoundedSafeQueue<V>
. La capacité maximale est fixée à la création de la file et la taille de la file ne devra jamais dépasser cette capacité. La méthode add
n'est donc plus adaptée car elle ne prend pas en compte la capacité maximale. On la remplace par une méthode put(V value)
qui ajoute value
s'il y a la place et sinon attend jusqu'à ce qu'une place se libère.
Écrire la classe BoundedSafeQueue<V>
et la tester avec différentes valeurs de capacité initiale.
Vérifier que l'on observe le comportement attendu quand on augmente le nombre de threads en jeu (10, 50, ...).
Dans cet exercice, on veut réaliser une classe Vote
. Cette classe thread-safe permet d'enregistrer
n
votes pour des String
. Quand les n
votes ont été enregistrés, on renvoie à chaque votant la String
qui a reçu le plus de votes (en cas d'égalité, on renvoie la plus petite dans l'ordre alphabétique ayant reçu le plus de votes). Le nombre n
de votes attendus est pris en paramètre par le constructeur.
La classe Vote
offre une seule méthode vote
qui sert à proposer son vote et qui bloque jusqu'à ce que les n
votes soient arrivés. Ensuite elle
renvoie le gagnant. Si vote
est appelée après que les n
votes aient été reçus, la méthode renvoie simplement le gagnant.
Le main
ci-dessous donne un exemple d'utilisation de la classe.
public static void main(String[] args) throws InterruptedException { var vote = new Vote(4); Thread.ofPlatform().start(() -> { try { Thread.sleep(2_000); System.out.println("The winner is " + vote.vote("un")); } catch (InterruptedException e) { throw new AssertionError(e); } }); Thread.ofPlatform().start(() -> { try { Thread.sleep(1_500); System.out.println("The winner is " + vote.vote("zero")); } catch (InterruptedException e) { throw new AssertionError(e); } }); Thread.ofPlatform().start(() -> { try { Thread.sleep(1_000); System.out.println("The winner is " + vote.vote("un")); } catch (InterruptedException e) { throw new AssertionError(e); } }); System.out.println("The winner is " + vote.vote("zero")); }
Écrire la classe Vote
et vérifier qu'elle passe les tests unitaires de VoteTest.java.
Vous pouvez utiliser une HashMap<String, Integer>
pour stocker le nombre de votes qu'a reçus chaque String
.
Voici une méthode permettant de récupérer le gagnant à partir de la HashMap
(on peut faire beaucoup plus joli en utlisant un Stream
) :
private String computeWinner() { var score = -1; String winner = null; for (var e : map.entrySet()) { var key = e.getKey(); var value = e.getValue(); if (value > score || (value == score && key.compareTo(winner) < 0)) { winner = key; score = value; } } return winner; }
Dans cet exercice, on va faire évoluer le programme de maximum thread-safe du TP précédent. Le thread main
démarre 4 threads, chacun d'eux fait une boucle infinie qui, toutes les secondes :
MAX_VALUE
;
main
a démarré les quatres threads, on veut qu'il attende qu'un thread ait proposé une valeur supérieure à 8_000 et qu'il affiche "Un thread a tiré un valeur supérieure à 8 000" (sans afficher cette valeur pour l'instant). Une fois que c'est le cas, le thread main
affichera le nombre maximum proposé par une thread toutes les secondes.
MAX_VALUE = 10_000
est une constante de la classe BlockingMaximum
que vous allez écrire par la suite.
Le thread main
et les 4 threads qu'il a démarré doivent communiquer au moyen d'un classe thread-safe BlockingMaximum
. Donnez le contrat de cette classe, c'est à dire les méthodes publiques de la classe ainsi que le comportement attendu.
Écrire le code du main
dans une classe Application
ainsi que les méthodes de BlockingMaximum
. Le programme va boucler à l'infini, c'est normal.
Thread[#22,Thread-2,5,main] a tiré 6296 Thread[#20,Thread-0,5,main] a tiré 1684 Thread[#21,Thread-1,5,main] a tiré 7227 Thread[#23,Thread-3,5,main] a tiré 30 Thread[#21,Thread-1,5,main] a tiré 8318 Thread[#20,Thread-0,5,main] a tiré 9208 Thread[#23,Thread-3,5,main] a tiré 6619 Thread[#22,Thread-2,5,main] a tiré 9653 Un thread a tiré un valeur supérieure à 8 000 Thread[#23,Thread-3,5,main] a tiré 5173 Thread[#22,Thread-2,5,main] a tiré 5777 Thread[#21,Thread-1,5,main] a tiré 5178 Thread[#20,Thread-0,5,main] a tiré 7996 Max courant : 9653 Thread[#22,Thread-2,5,main] a tiré 435 Thread[#21,Thread-1,5,main] a tiré 8350 Thread[#23,Thread-3,5,main] a tiré 909 Thread[#20,Thread-0,5,main] a tiré 1273 Max courant : 9653 ...
(Optionnel) Modifier le code pour qu'au lieu d'afficher "Un thread a tiré un valeur supérieure à 8 000", le main affiche la première valeur supérieure à 8 000 proposée. Attention c'est plus subtile qu'il n'y paraît.