:: Enseignements :: ESIPE :: E4INFO :: 2013-2014 :: Java Réseau I - Concurrence et E/S ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Thread, Interruption et variable de thread |
La version d'Eclipse installée sur vos machines ne supportent pas la version 8
de Java, donc pour ce TP et les TPs suivant nous allons utiliser
une version spécifique disponible ici
/home/ens/forax/java8/eclipse-lambda/eclipse
Eclipse fonctionnant sur le principe de workspace, il est plus simple
d'utiliser un workspace pour java 7 et un workspace pour Java 8.
Une fois Eclipse lancée, configurer le workspace utiliser par celui-ci
pour qu'il corresponde à un répertoire
workspace-eclipse8 dans votre répertoire personnel.
Enfin, en allant dans les préférences (Window / Preferencew),
il faut indiquer qu'il faut utiliser le jdk8 disponible dans le répertoire
/home/ens/forax/java8/jdk1.8.0-lambda
dans Java / Installed JREs / Add... et demander au compilateur
d'utiliser la syntaxe de Java 8 dans Java / Compiler / Compliance level.
Si vous voulez utiliser ces versions chez vous,
Exercice 1 - Hello Thread
On souhaite créer deux threads exécutant le même code.
Pour différencier les deux threads, lors de la construction
de celles-ci, un entier unique (
id) sera fourni à chacune,
0 pour la première et 1 pour la seconde.
Chaque thread exécutera le même code qui consiste à afficher
hello suivi du numéro de la thread ainsi que la
valeur d'un compteur indiquant le nombre de fois que la thread
a affiché ce message.
Par exemple, on pourra obtenir ce type d'affichage :
...
hello 0 10714
hello 0 10715
hello 0 10716
hello 0 10717
hello 1 15096
hello 1 15097
hello 1 15098
hello 1 15099
...
-
Avant de commencer à coder, expliquer sur l'exemple ci-dessus pourquoi selon vous le compteur
de hello 0 est beaucoup plus petit que le compteur de hello 1? Est-ce que
cette observation sera la même à chaque exécution? Peut on le contrôler?
-
Toujours avant de commencer à coder, rappeler à quoi sert l'interface Runnable ?
-
Créer maintenant une classe HelloRunnable qui implante l'interface Runnable,
qui prend à la construction un numéro d'identification et qui dans la méthode run
fait une boucle en utilisant un index 1 à 10 000 qui affiche hello id index
(comme dans l'exemple ci-dessus).
Ecrire dans une autre classe HelloThread une méthode main qui crée
deux HelloRunnable, un avec l'id 0 et un autre avec l'id 1, puis qui crée
deux threads (un sur chaque runnable) et démarre ceux-ci en concurrence. Testez votre code
dans la console d'eclipse et dans une fenêtre de terminal.
-
Changer votre code pour que l'on puisse choisir lors de
l'exécution du programme (1er argument, args[0]) le nombre de threads que l'on veut lancer
en concurrence (si l'argument est 2, on aura le même comportement que précédemment).
Rappel: Integer.parseInt prend une chaine de caractère en paramètre et renvoie un entier.
-
Modifier le main de HelloThread pour utiliser la syntaxe des lambdas-expressions
pour spécifier le Runnable plutôt que d'utiliser la classe HelloRunnable.
-
Tester la méthode setPriority(int) de Thread.
Exercice 2 - Modification d'une variable en concurrence
On souhaite créer deux threads qui changent le même champ
d'un même objet :
-
Qu'affiche le code suivant avec la ligne de commande : java Test ?
Expliquer.
-
Pourquoi l'affichage n'évolue plus au bout d'un laps de temps ?
Peut-on en déduire qu'il n'y a plus de problème de concurrence ?
-
Comment doit on faire pour être sûr que chaque thread voit
les modifications effectuées sur une variable par l'autre thread ?
Exercice 3 - Coitus interruptus
Sur la base de la classe HelloThread du premier exercice, on
souhaite maintenant permettre à l'utilisateur, en tapant un nombre,
d'interrompre la thread ayant cet identificateur.
-
Avant tout, expliquer les différences entre les méthodes interrupted
et isInterrupted de la classe Thread.
-
Recopier le code de la classe HelloThread en une nouvelle
classe Interruptus et utiliser un scanner (java.util.Scanner)
pour lire sur l'entrée standard des commandes de contrôle
(à partir de la thread principale).
Pour éviter de surcharger la console par des affichages, on souhaite simplement
que chaque thread incrémente un index et affiche lorsqu'elle est démarée et
lorsqu'elle est interrompue. Le code que devra excuter chaque thread doit donc
être le suivant (à compléter):
int index;
System.out.println("Thread " + Thread.currentThread().getName() + " started.");
for(index = 0; /* something to complete here */; index++) {
// do nothing
}
System.out.println("Thread " + Thread.currentThread().getName() + " has count till "
+ index + " before being interrupted.");
Reste ensuite à implanter les commandes suivantes, lorsqu'elle sont lues sur le scanner :
-
kill id afin de tuer la thread d'identificateur id.
On utilisera la méthode interrupt() pour interrompre la thread.
-
status id afin d'afficher l'état (state) de la thread d'identificateur id.
Il y a deux façons d'arrêter le programme, soit toutes les threads ont été interrompues,
soit l'utilisateur tape Control D dans le terminal
(Scanner.hasNext() renvoi false)
Il est possible de surveiller la machine virtuelle avec la commande jconsole
(mémoire allouée sur le tas, classes chargées, threads en activité...).
Lancer cette commande, sélectionner le processus à surveiller et vérifier que les threads sont bien interrompues.
-
Plutôt que // do nothing, on souhaite maintenant que chaque
thread affiche où elle en est de l'incrémentation de son compteur, mais pour éviter
de remplir trop vite la console, on peut utiliser la méthode Thread.sleep()
entre deux tours de boucle. Quel problème cela pose-t-il?
Que doit on faire de l'exception levée par cette méthode?
© Université de Marne-la-Vallée