:: Enseignements :: ESIPE :: E4INFO :: 2017-2018 :: Concurrence ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Synchronized, lock, trylock |
Exercice 1 - Tableau d'honneur
Une école possède un tableau d'honneur (où l'on met le nom de l'élève le plus méritant) qui
peut être mis à jour de façon informatique. Il n'en faut pas plus pour que John Doe et Jane Odd,
nos deux apprentis hackers, écrivent un petit programme qui met à jour automatiquement
le tableau d'honneur avec leurs noms.
Malheureusement, la classe
HonorBoard n'est pas
thread safe, donc le code
fait n'importe quoi.
-
Rappeler ce que cela veut dire qu'une classe n'est pas thread safe.
-
Expliquer pourquoi la classe HonorBoard n'est pas thread safe.
Si vous ne voyez pas, faîtes un grep "John Odd" sur la sortie du programme.
Rappel général: un test qui plante indique un problème, un test qui ne plante pas
n'indique rien du tout.
-
Modifiez le code de la classe HonorBoard pour la rendre thread safe
en utilisant des blocs synchronized.
Pensez à vérifier avec grep sur la sortie comme précédemment
(pendant plusieurs minutes).
-
Maintenant que votre classe est thread safe, peut-on remplacer la ligne:
System.out.println(board);
par la ligne:
System.out.println(board.getFirstName() + ' ' + board.getLastName());
avec les deux getters définis comme d'habitude ?
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
Exercice 2 - Tableau d'honneur (2)
Reprendre le code de la classe
HonorBoard de l'exercice précédent.
On cherche maintenant à remplacer les usages du mot-clé
synchronized par un verrou ré-entrant
du package
java.util.concurrent.lock.
-
Rappeler ce que ré-entrant veut dire.
-
Rendre la classe HonorBoard thread safe en utilisant un verrou ré-entrant.
Attention à bien libérer le verrou si une exception est levée.
Exercice 3 - Coitus interruptus
On souhaite avoir 4 threads qui affichent chacune leur numéro et un compteur indéfiniment
(chaque thread a son propre compteur). Pour éviter de faire chauffer la machine,
l'affichage se fera une fois par seconde (en utilisant
Thread.sleep()).
De plus, la thread
main va lire des entiers sur l'entrée standard
et si l'utilisateur entre une valeur correspondant au numéro d'une thread,
cette dernière sera arrêtée.
Le code pour lire sur l'entrée standard est le suivant:
System.out.println("enter a thread id:");
try(Scanner scanner = new Scanner(System.in)) {
while(scanner.hasNextInt()) {
int threadId = scanner.nextInt();
...
}
}
Note: dans les vrais programmes, on utilise rarement le
Scanner car il est très lent
(comme le
scanf en C), on utilise plutôt un
BufferedReader ou
Files.lines.
Rappel: on utilise Ctrl-D (Ctrl-Z sous Microsoft Windows) pour indiquer au terminal
qu'il faut fermer l'entrée standard.
-
Pourquoi n'est il pas possible d’arrêter une thread de façon non coopérative ?
-
Qu'est-ce qu'une opération bloquante?
À quoi sert la méthode d'instance interrupt() de la classe Thread?
Expliquer comment interrompre une thread en train d'effectuer une opération bloquante et le faire sur l'exemple suivant (en faisant afficher "end" quand la thread est interrompue).
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
...
Thread.sleep(1_000);
...
});
t.start();
Thread.sleep(1_000);
t.interrupt();
}
-
Expliquer, sur l'exemple suivant, comment utiliser la méthode
Thread.interrupted (noter qu'elle est statique)
pour arrêter une thread dans le cas où il n'y a pas d'opération bloquante. Faire afficher "end" et la valeur de forNothing quand la thread est interrompue.
private static int slow() {
int result = 1;
for (int i = 0; i < 1_000_000; i++) {
result += (result * 7) % 513;
}
return result;
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
int forNothing = 0;
while (true) {
...
forNothing += slow();
...
}
});
t.start();
Thread.sleep(1_000);
t.interrupt();
}
-
Comment faire pour interrompre la thread à coup sûr, si elle effectue à la fois des opérations bloquantes et non bloquantes? Par exemple:
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while(...){
int forNothing = slow();
...
Thread.sleep(1_000);
...
forNothing+=slow();
}
});
t.start();
Thread.sleep(1_000);
t.interrupt();
}
-
Expliquer la (trop) subtile différence entre les méthodes Thread.interrupted
et thread.isInterrupted de la classe Thread.
Pourquoi dit-on que la méthode Thread.interrupted est mal nommée ?
-
Comment faire pour que le programme se termine si l'on fait un Ctrl-D dans le terminal ?
Exercice 4 - Le déjeuner des philosophes
La situation est la suivante :
cinq philosophes (initialement, mais il peut y en avoir beaucoup plus) se trouvent autour d'une table ronde;
chaque philosophe a, devant lui, un plat de spaghetti et entre chaque assiette se trouve une fourchette.
Pour pouvoir manger, un philosophe doit prendre deux fourchettes, celle à sa droite et celle à sa gauche.
Un de vos collègues propose le code suivant:
-
Quel est le problème du code ci-dessus ?
Dans quelle(s) condition(s) se produit-il ?
Note: vous avez le droit de l'exécuter si vous ne voyez pas.
-
Est-il possible d'avoir deux philosophes qui mangent en même temps ?
Est-ce quelque chose qui est normal ou pas ?
-
Modifier le code pour corriger le problème.
Note: il existe deux façons, une plus belle que l'autre :)
© Université de Marne-la-Vallée