L'examen est composé d'une partie écrite sur feuille de 40 minutes maximum, à faire en premier et de deux exercices qui peuvent être traités dans l'ordre que vous voulez.
Rappel : si ce n'est pas déjà le cas, vous devez configurer le workspace d'Eclipse (File > Switch WorkSpace) pour qu'il corresponde au répertoire EXAM présent dans le home de votre session de TP noté.
Vérifier que tous vos fichiers sont bien dans le répertoire EXAM. Tout ce qui n'est pas dans ce répertoire est perdu quand vous vous déconnectez.
La javadoc 23 est là : https://igm.univ-mlv.fr/~juge/javadoc-23/.
Vous avez le droit de consulter les transparents du cours pendant tout l'examen.
ReentrantLock
)Les classes de cet exercice doivent être dans package fr.uge.concurrence.exo1.
Le but de cet exercice est de créer une classe thread-safe ThreadMatching
qui va permettre à plusieurs threads de s'associer par paires (en récupérant un id commun et unique pour la paire).
Pour ce faire, la classe ThreadMatching
possède une méthode Optional<Integer> register(String ticket)
. Elle prend en paramètre une chaîne de caractères ticket
qui permet de faire les associations. Lorsqu'un thread (noté t1) utilise register
avec un ticket inconnu, on lui affecte un identifiant id et il attend. Et si un autre thread (noté t2) utilise register
avec le même ticket, il sont associés : t2 sort immédiatement de la méthode qui renvoie id et t1 est débloqué et il sortira de la méthode qui renvoie aussi id. Le ticket est alors oublié, il pourra être utilisé à nouveau par une autre paire de threads. Si un troisième thread (noté t3) arrive avec le même ticket avant que t1 soit débloqué, la méthode renvoie directement un Optional
vide. Sinon, ça recommence et t3 va attendre d'être associé à un autre thread, et tous deux recevront un nouvel identifiant.
Indication 1 : pour les identifiants, il suffit d'utiliser un compteur que l'on incrémente à chaque fois qu'un nouveau ticket est proposé.
Indication 2 : à chaque ticket, il faut associer l'identifiant correspondant et de quoi savoir où on en est dans l'association (déjà 1 thread, déjà 2 threads, ...)
On rappelle qu'il ne peut y avoir aucune synchronisation dans le code du main
et que les méthodes de la classe thread-safe ne doivent pas faire d'affichage.
Écrire la classe thread-safe ThreadMatching
et sa méthode register()
. Pour cette exercice, la gestion de la concurrence doit être faite avec des ReentrantLock
.
Vous pouvez tester votre code dans une classe MainMatching
avec le code suivant qui démarre 20 threads qui essaient en boucle de trouver un partenaire. Ils affichent lorsqu'ils s'inscrivent, et lorsqu'un paire est constituée, chaque thread affiche avec qui il a été associé. Normalement, le programme ne s'arrête pas.
Remarque : si vous voulez vous convaincre que les associations fonctionnent, vous pouvez tenter de supprimer le sleep
ou de le réduire à quelques millisecondes).
public static void main(String[] args) { var matching = new ThreadMatching(); var nbThreads = 20; for (var j = 0; j < nbThreads; j++) { var i = j; Thread.ofPlatform().start(() -> { for (;;) { try { Thread.sleep(ThreadLocalRandom.current().nextInt(1500, 3000)); var name = Thread.currentThread().getName(); var ticket = "t" + (i % (nbThreads / 3)); System.out.println(name + " registers " + ticket); var id = matching.register(ticket); if (id.isEmpty()) { System.out.println("NO MATCH for " + name); continue; } System.out.println("MATCH for " + name + " (" + ticket + ") : id = " + id.orElseThrow()); } catch (InterruptedException e) { // TODO } } }); } }
Dupliquer le code de ThreadMatching
de la question 1 dans une classe ThreadMatchingQ2
. On ajoute la constante suivante dans la classe : public static final int MAX_WAITNG = 4;
et la contrainte qu'il ne peut pas y avoir plus de MAX_WAITNG
threads en train d'attendre d'être associé. S'il y a déjà le maximum de threads en attente et qu'un thread appelle register
avec un nouveau ticket (c'est à dire qu'aucun thread n'attend avec ce ticket), il reçoit immédiatement un Optional
vide. Sinon, il est associé comme précédemment. De plus, les associations rapportent des points au ThreadMatchingQ2
: 1 point pour une association réussie, et -5 points si un thread est arrivé alors que le nombre max est atteint. Le score n'est pas modifié si un thread reçoit un Optional
vide. Ajouter une méthode int points()
qui permet de consulter le total courant des points et une autre int upToPoints(int nb)
qui bloque jusqu'à ce que le total des points ait dépassé nb
en valeur absolue. Elle renvoie alors le total courant des points.
(BONUS) Compléter le code du main
fournit pour que le nombre de points soit affiché toutes les 2 secondes et que le programme s'arrête si le total dépasse 30 en valeur absolue.
Thread-14 registers t4 Thread-1 registers t1 Thread-19 registers t9 Thread-3 registers t3 Thread-9 registers t9 MATCH for Thread-9 (t9) : id = 2 MATCH for Thread-19 (t9) : id = 2 Thread-13 registers t3 MATCH for Thread-13 (t3) : id = 3 MATCH for Thread-3 (t3) : id = 3 Thread-6 registers t6 Thread-16 registers t6 MATCH for Thread-16 (t6) : id = 4 MATCH for Thread-6 (t6) : id = 4 Thread-7 registers t7 Thread-5 registers t5 Thread-11 registers t1 MATCH for Thread-11 (t1) : id = 1 MATCH for Thread-1 (t1) : id = 1 Thread-15 registers t5 MATCH for Thread-15 (t5) : id = 6 MATCH for Thread-5 (t5) : id = 6 Thread-17 registers t7 MATCH for Thread-17 (t7) : id = 5 MATCH for Thread-7 (t7) : id = 5 Thread-0 registers t0 Thread-12 registers t2 Thread-10 registers t0 MATCH for Thread-10 (t0) : id = 7 MATCH for Thread-0 (t0) : id = 7 Thread-2 registers t2 MATCH for Thread-2 (t2) : id = 8 MATCH for Thread-12 (t2) : id = 8 Thread-18 registers t8 Thread-4 registers t4 MATCH for Thread-4 (t4) : id = 0 MATCH for Thread-14 (t4) : id = 0 Thread-8 registers t8 MATCH for Thread-8 (t8) : id = 9 MATCH for Thread-18 (t8) : id = 9 ------------------------------------------- 10 Thread-11 registers t1 Thread-3 registers t3 Thread-13 registers t3 MATCH for Thread-13 (t3) : id = 11 MATCH for Thread-3 (t3) : id = 11 Thread-17 registers t7 Thread-1 registers t1 MATCH for Thread-1 (t1) : id = 10 MATCH for Thread-11 (t1) : id = 10 Thread-12 registers t2 Thread-19 registers t9 Thread-5 registers t5 Thread-9 registers t9 MATCH for Thread-9 (t9) : id = 14 MATCH for Thread-19 (t9) : id = 14 Thread-0 registers t0 Thread-4 registers t4 NO MATCH for Thread-4 Thread-2 registers t2 MATCH for Thread-2 (t2) : id = 13 MATCH for Thread-12 (t2) : id = 13 Thread-15 registers t5 MATCH for Thread-15 (t5) : id = 15 MATCH for Thread-5 (t5) : id = 15 Thread-16 registers t6 Thread-6 registers t6 MATCH for Thread-6 (t6) : id = 17 MATCH for Thread-16 (t6) : id = 17 Thread-7 registers t7 MATCH for Thread-7 (t7) : id = 12 MATCH for Thread-17 (t7) : id = 12 Thread-8 registers t8 Thread-10 registers t0 MATCH for Thread-10 (t0) : id = 16 MATCH for Thread-0 (t0) : id = 16 Thread-14 registers t4 Thread-18 registers t8 MATCH for Thread-18 (t8) : id = 18 MATCH for Thread-8 (t8) : id = 18 Thread-3 registers t3 ------------------------------------------- 14 Thread-9 registers t9 Thread-15 registers t5 Thread-4 registers t4 MATCH for Thread-14 (t4) : id = 19 MATCH for Thread-4 (t4) : id = 19 Thread-0 registers t0 Thread-13 registers t3 MATCH for Thread-13 (t3) : id = 20 MATCH for Thread-3 (t3) : id = 20 Thread-19 registers t9 MATCH for Thread-19 (t9) : id = 21 MATCH for Thread-9 (t9) : id = 21 Thread-11 registers t1 Thread-1 registers t1 MATCH for Thread-1 (t1) : id = 24 MATCH for Thread-11 (t1) : id = 24 Thread-5 registers t5 MATCH for Thread-5 (t5) : id = 22 MATCH for Thread-15 (t5) : id = 22 Thread-2 registers t2 Thread-17 registers t7 Thread-18 registers t8 Thread-7 registers t7 MATCH for Thread-7 (t7) : id = 26 MATCH for Thread-17 (t7) : id = 26 Thread-16 registers t6 Thread-6 registers t6 MATCH for Thread-6 (t6) : id = 28 MATCH for Thread-16 (t6) : id = 28 Thread-12 registers t2 MATCH for Thread-12 (t2) : id = 25 MATCH for Thread-2 (t2) : id = 25 Thread-10 registers t0 MATCH for Thread-10 (t0) : id = 23 MATCH for Thread-0 (t0) : id = 23 Thread-8 registers t8 MATCH for Thread-8 (t8) : id = 27 MATCH for Thread-18 (t8) : id = 27 Thread-14 registers t4 Thread-4 registers t4 MATCH for Thread-4 (t4) : id = 29 MATCH for Thread-14 (t4) : id = 29 Thread-15 registers t5 Thread-13 registers t3 Thread-7 registers t7 ------------------------------------------- 25 Thread-9 registers t9 Thread-1 registers t1 NO MATCH for Thread-1 Thread-19 registers t9 MATCH for Thread-19 (t9) : id = 33 MATCH for Thread-9 (t9) : id = 33 Thread-11 registers t1 Thread-6 registers t6 NO MATCH for Thread-6 Thread-3 registers t3 MATCH for Thread-3 (t3) : id = 31 MATCH for Thread-13 (t3) : id = 31 Thread-5 registers t5 MATCH for Thread-5 (t5) : id = 30 MATCH for Thread-15 (t5) : id = 30 Thread-0 registers t0 Thread-16 registers t6 Thread-8 registers t8 NO MATCH for Thread-8 Thread-17 registers t7 MATCH for Thread-17 (t7) : id = 32 MATCH for Thread-7 (t7) : id = 32 Thread-2 registers t2 Thread-12 registers t2 MATCH for Thread-12 (t2) : id = 37 MATCH for Thread-2 (t2) : id = 37 Thread-4 registers t4 Thread-10 registers t0 MATCH for Thread-10 (t0) : id = 35 MATCH for Thread-0 (t0) : id = 35 Thread-18 registers t8 Thread-9 registers t9 NO MATCH for Thread-9 Thread-14 registers t4 MATCH for Thread-14 (t4) : id = 38 MATCH for Thread-4 (t4) : id = 38 Thread-15 registers t5 Thread-19 registers t9 NO MATCH for Thread-19 Thread-17 registers t7 NO MATCH for Thread-17 Thread-8 registers t8 MATCH for Thread-8 (t8) : id = 39 MATCH for Thread-18 (t8) : id = 39 Thread-5 registers t5 MATCH for Thread-5 (t5) : id = 40 MATCH for Thread-15 (t5) : id = 40 ------------------------------------------- 4 Thread-1 registers t1 MATCH for Thread-1 (t1) : id = 34 MATCH for Thread-11 (t1) : id = 34 Thread-13 registers t3 Thread-3 registers t3 MATCH for Thread-3 (t3) : id = 41 MATCH for Thread-13 (t3) : id = 41 Thread-6 registers t6 MATCH for Thread-6 (t6) : id = 36 MATCH for Thread-16 (t6) : id = 36 Thread-0 registers t0 Thread-10 registers t0 MATCH for Thread-10 (t0) : id = 42 MATCH for Thread-0 (t0) : id = 42 Thread-2 registers t2 Thread-12 registers t2 MATCH for Thread-12 (t2) : id = 43 MATCH for Thread-2 (t2) : id = 43 Thread-7 registers t7 Thread-14 registers t4 Thread-19 registers t9 Thread-4 registers t4 MATCH for Thread-4 (t4) : id = 45 MATCH for Thread-14 (t4) : id = 45 Thread-15 registers t5 Thread-9 registers t9 MATCH for Thread-9 (t9) : id = 46 MATCH for Thread-19 (t9) : id = 46 Thread-1 registers t1 Thread-13 registers t3 Thread-16 registers t6 NO MATCH for Thread-16 Thread-5 registers t5 MATCH for Thread-5 (t5) : id = 47 MATCH for Thread-15 (t5) : id = 47 Thread-12 registers t2 Thread-0 registers t0 NO MATCH for Thread-0 Thread-17 registers t7 MATCH for Thread-17 (t7) : id = 44 MATCH for Thread-7 (t7) : id = 44 Thread-3 registers t3 MATCH for Thread-3 (t3) : id = 49 MATCH for Thread-13 (t3) : id = 49 Thread-6 registers t6 Thread-8 registers t8 Thread-18 registers t8 MATCH for Thread-18 (t8) : id = 52 MATCH for Thread-8 (t8) : id = 52 Thread-11 registers t1 MATCH for Thread-11 (t1) : id = 48 MATCH for Thread-1 (t1) : id = 48 ------------------------------------------- 6 Thread-2 registers t2 MATCH for Thread-2 (t2) : id = 50 MATCH for Thread-12 (t2) : id = 50 Thread-14 registers t4 Thread-10 registers t0 Thread-4 registers t4 MATCH for Thread-4 (t4) : id = 53 MATCH for Thread-14 (t4) : id = 53 Thread-15 registers t5 Thread-8 registers t8 Thread-0 registers t0 MATCH for Thread-0 (t0) : id = 54 MATCH for Thread-10 (t0) : id = 54 Thread-16 registers t6 MATCH for Thread-16 (t6) : id = 51 MATCH for Thread-6 (t6) : id = 51 Thread-9 registers t9 Thread-7 registers t7 Thread-1 registers t1 NO MATCH for Thread-1 Thread-19 registers t9 MATCH for Thread-19 (t9) : id = 57 MATCH for Thread-9 (t9) : id = 57 Thread-5 registers t5 MATCH for Thread-5 (t5) : id = 55 MATCH for Thread-15 (t5) : id = 55 Thread-18 registers t8 MATCH for Thread-18 (t8) : id = 56 MATCH for Thread-8 (t8) : id = 56 Thread-17 registers t7 MATCH for Thread-17 (t7) : id = 58 MATCH for Thread-7 (t7) : id = 58 Thread-2 registers t2 Thread-13 registers t3 Thread-3 registers t3 MATCH for Thread-3 (t3) : id = 60 MATCH for Thread-13 (t3) : id = 60 Thread-11 registers t1 Thread-4 registers t4 Thread-12 registers t2 MATCH for Thread-12 (t2) : id = 59 MATCH for Thread-2 (t2) : id = 59 Thread-16 registers t6 ------------------------------------------- 11 Thread-14 registers t4 MATCH for Thread-14 (t4) : id = 62 MATCH for Thread-4 (t4) : id = 62 Thread-10 registers t0 Thread-19 registers t9 Thread-18 registers t8 NO MATCH for Thread-18 Thread-6 registers t6 MATCH for Thread-6 (t6) : id = 63 MATCH for Thread-16 (t6) : id = 63 Thread-5 registers t5 Thread-15 registers t5 MATCH for Thread-15 (t5) : id = 66 MATCH for Thread-5 (t5) : id = 66 Thread-0 registers t0 MATCH for Thread-0 (t0) : id = 64 MATCH for Thread-10 (t0) : id = 64 Thread-8 registers t8 Thread-9 registers t9 MATCH for Thread-19 (t9) : id = 65 MATCH for Thread-9 (t9) : id = 65 Thread-3 registers t3 Thread-1 registers t1 MATCH for Thread-1 (t1) : id = 61 MATCH for Thread-11 (t1) : id = 61 Thread-4 registers t4 Thread-13 registers t3 MATCH for Thread-13 (t3) : id = 68 MATCH for Thread-3 (t3) : id = 68 Thread-7 registers t7 Thread-2 registers t2 Thread-17 registers t7 MATCH for Thread-17 (t7) : id = 70 MATCH for Thread-7 (t7) : id = 70 Thread-14 registers t4 MATCH for Thread-14 (t4) : id = 69 MATCH for Thread-4 (t4) : id = 69 Thread-12 registers t2 MATCH for Thread-12 (t2) : id = 71 MATCH for Thread-2 (t2) : id = 71 Thread-16 registers t6 Thread-0 registers t0 Thread-19 registers t9 Thread-18 registers t8 MATCH for Thread-18 (t8) : id = 67 MATCH for Thread-8 (t8) : id = 67 Thread-10 registers t0 MATCH for Thread-10 (t0) : id = 73 MATCH for Thread-0 (t0) : id = 73 Thread-9 registers t9 MATCH for Thread-9 (t9) : id = 74 MATCH for Thread-19 (t9) : id = 74 Thread-6 registers t6 MATCH for Thread-6 (t6) : id = 72 MATCH for Thread-16 (t6) : id = 72 ------------------------------------------- 20 Thread-15 registers t5 Thread-5 registers t5 MATCH for Thread-5 (t5) : id = 75 MATCH for Thread-15 (t5) : id = 75 Thread-17 registers t7 Thread-1 registers t1 Thread-7 registers t7 MATCH for Thread-7 (t7) : id = 76 MATCH for Thread-17 (t7) : id = 76 Thread-12 registers t2 Thread-11 registers t1 MATCH for Thread-11 (t1) : id = 77 MATCH for Thread-1 (t1) : id = 77 Thread-13 registers t3 Thread-3 registers t3 MATCH for Thread-3 (t3) : id = 79 MATCH for Thread-13 (t3) : id = 79 Thread-19 registers t9 Thread-14 registers t4 Thread-16 registers t6 Thread-0 registers t0 NO MATCH for Thread-0 Thread-2 registers t2 MATCH for Thread-2 (t2) : id = 78 MATCH for Thread-12 (t2) : id = 78 Thread-9 registers t9 MATCH for Thread-9 (t9) : id = 80 MATCH for Thread-19 (t9) : id = 80 Thread-4 registers t4 MATCH for Thread-4 (t4) : id = 81 MATCH for Thread-14 (t4) : id = 81 Thread-5 registers t5 Thread-8 registers t8 Thread-10 registers t0 Thread-18 registers t8 MATCH for Thread-18 (t8) : id = 84 MATCH for Thread-8 (t8) : id = 84 Thread-15 registers t5 MATCH for Thread-15 (t5) : id = 83 MATCH for Thread-5 (t5) : id = 83 Thread-6 registers t6 MATCH for Thread-6 (t6) : id = 82 MATCH for Thread-16 (t6) : id = 82 Thread-11 registers t1 ------------------------------------------- 25 Thread-13 registers t3 Thread-3 registers t3 MATCH for Thread-3 (t3) : id = 87 MATCH for Thread-13 (t3) : id = 87 Thread-1 registers t1 MATCH for Thread-1 (t1) : id = 86 MATCH for Thread-11 (t1) : id = 86 Thread-0 registers t0 MATCH for Thread-0 (t0) : id = 85 MATCH for Thread-10 (t0) : id = 85 Thread-7 registers t7 Thread-12 registers t2 Thread-17 registers t7 MATCH for Thread-17 (t7) : id = 88 MATCH for Thread-7 (t7) : id = 88 Thread-18 registers t8 Thread-19 registers t9 Thread-15 registers t5 Thread-9 registers t9 MATCH for Thread-9 (t9) : id = 91 MATCH for Thread-19 (t9) : id = 91 FINAL SCORE : 30
synchronized
)Les classes de cet exercice doivent être dans package fr.uge.concurrence.exo2.
On veut écrire un programme qui permet de constituer une équipe d'au moins MIN_TEAM_SIZE
joueurs (représentés par différents threads) pour un jeu coopératif. Le programme attendra que suffisamment de threads ait demandé à faire partie de l'équipe pour démarrer le jeu. Mais comme ça peut prendre un peu de temps, les joueurs doivent avoir la possibilité de se rétracter tant que l'équipe n'est pas prête. Le tout doit se passer de façon concurrente, en utilisant une classe thread-safe CoopGame
appropriée.
La classe CoopGame
contiendra la constante publique suivante :
public class CoopGame { public static final int MIN_TEAM_SIZE = 5; }
Dans le programme que vous allez écrire, 7 threads vont essayer, en boucle de s'inscrire puis de se désinscrire dans une équipe de CoopGame
. Chacun attend un temps aléatoire entre 0 et 200 millisecondes entre chaque tentative (d'inscription ou de désinscription) :
Thread.sleep(ThreadLocalRandom.current().nextInt(200));À partir du moment où l'équipe a au moins
MIN_TEAM_SIZE
joueurs, il est possible de se désinscrire uniquement si on ne repasse pas sous le seuil de MIN_TEAM_SIZE
joueurs, sinon, le thread doit être bloqué jusqu'à ce qu'il soit possible de se désinscrire (c'est à dire qu'il y a au moins un joueur en plus).
main
attend que l'équipe soit au complet (qu'elle ait au moins MIN_TEAM_SIZE
joueurs), et lorsque c'est le cas, le main
affiche la composition de l'équipe et le programme s'arrête. Idéalement, lorsque le main
est débloqué, plus aucun thread ne doit pouvoir s'inscrire ou se désinscrire.
Trouvez le contrat et écrivez le code d'une classe thread-safe CoopGame
qui permettra de faire communiquer tous les threads ensemble (dans cet exercice, la synchronisation devra être faite uniquement avec des blocs synchronized
).
Dans le main
d'une classe Application
écrivez le code réalisant le programme décrit plus haut.
On rappelle qu'il ne peut y avoir aucune synchronisation (y compris pas de join
) dans le code du main
et que les méthodes de la classe thread-safe ne doivent pas faire d'affichage.
Pour vous aider, voici un exemple d'affichage.
t3 in t8 in t7 in t5 in t8 try out t8 out t4 in t3 try out t5 try out t5 out t3 out t5 in t2 in t6 in t1 in t7 try out Game on with team : t4, t6, t5, t7, t2, t1
Modifier votre programme pour pouvoir, en plus, afficher à intervalles de temps réguliers (toutes les 50 millisecondes), combien de threads sont dans l'équipe, combien se sont inscrits (mais sont peut-être déjà désinscrits) et combien se sont désistés depuis le début du programme. Attention les nombres doit êtres cohérents : le nombre de personnes dans l'équipe doit correspondre la différence entre les inscriptions et les désistements.
Pour vous aider, voici un exemple d'affichage.
t2 in In team = 1, in = 1, out = 0 t5 in t3 in t2 try out t2 out In team = 2, in = 3, out = 1 t1 in t1 try out t1 out t7 in t7 try out t7 out t1 in In team = 3, in = 6, out = 3 t2 in t7 in t1 try out Game on with team : t7, t5, t3, t2, t1