Synchronisation de threads en Java TP1 : Observation V.Marangozova-Martin 1 Threads en Java Vous êtes habitués à écrire des programmes séquentiels i.e des programmes qui n’ont qu’un seul flot d’exécution qui exécute les instructions l’une après l’autre. Les threads permettent d’avoir plusieurs activités en parallèle dans un programme. Ce sont plusieurs flots d’exécution qui exécutent le même code et qui partagent le même espace d’adressage (celui du processus qui les a créés). Les threads peuvent partager ainsi des données et des ressources système (fichiers ouverts, sockets, etc.). La machine virtuelle Java 1 s’exécute comme un processus standard sur votre système. Les activités parallèles au sein de cette machine prennent la forme de threads. Les threads Java peuvent être implémentés de deux manières. Utilisation de la classe Thread La première méthode est d’étendre la classe prédéfinie Thread : // classes et interfaces predefinies Java , JDK interface Runnable { void run (); } public class Thread extends Object implements Runnable { void run () {...} void start () {...} ... } 1 Une machine virtuelle est généralement utilisée pour émuler un autre matériel que celui sur lequel a lieu l’execution. Elle permet l’exécuion de systèmes d’exploitation, de bibliothèques et d’applicatons écrits pour d’autre types de matériel. 1 Miage3, 2006-2007 2 public class Compteur extends Thread { public void run () {...} } public static main () { Compteur c = new Compteur (); c . start (); } } L’héritage à partir de Thread est contraignant car il empêche tout autre héritage (en Java, une classe ne peut hériter que d’une seule autre classe). Utilisation de l’interface Runnable La deuxième manière de faire est d’implémenter l’interface Runnable. Ceci permet l’héritage d’autres classes et l’implémentation d’autres interfaces. interface Runnable { void run (); } public class Thread extends Object implements Runnable { void run () {...} void start () {...} ... } public class Compteur implements Runnable{ public void run () {...} } public static main () { Compteur c = new Compteur (); new Thread( c ). start (); } } } 2 Préparation de l’environnement de travail Les étudiants travailleront en binôme. Pour les séances de TP, créer un répertoire dédié dans votre arborescence. Par exemple, <nom de login>/SR/. Pour chaque TP, créer un répertoire dédié (<nom de login>/SR/TP1, <nom de login>/SR/TP2, etc.). Les classes java seront dans un sous-répertoire src (contenant les sources). Les classes compilées seront dans un sous-répertoire classes. Miage3, 2006-2007 3 Pour compiler, se positionner dans le répertoire contenant src et classes et taper la bonne commande. Surtout, ne pas aller dans src pour compiler et ensuite copier les classes dans classes... 3 TP1 : Observation de threads L’objectif de ce TD/TP est de vous faire programmer des threads en Java, de vous faire observer le comportement des programmes à activités parallèles (multi-threadés) et de vous montrer le besoin de synchronisation entre threads. 3.1 Environnement de travail Nous travaillerons dans un environnement UNIX. Suivant les salles de TD/TP, la connexion aux serveurs de l’UFR est soit directe, soit il faut passer par XWin (à partir de postes Windows). Nous encourageons vivement l’utilisation de la ligne de commande i.e les commandes de compilation et de lancement seront à taper dans un terminal. L’utilisation d’Eclipse est possible. Cependant, attention, les makefiles ne seront pas fournis et si vous voulez utiliser Eclipse, ce sera à votre charge de créer vos projets. Cela voudrait dire configurer le CLASSPATH, les répertoires contenant les classes sources et les classes compilées pour que votre projet fonctionne correctement. Les programmes Java pour ce TD/TP se trouvent dans le répertoire suivant : ∼marangov/PUBLIC/MIAGE3/TP1.tgz Créer le répertoire TP1 chez vous, décompresser avec la commande > tar xzvf TP1 . tgz 3.2 exempleThread1.java Compiler et exécuter le programme exempleThread1.java (pour exécuter plusieurs fois, il est possible d’utiliser exec.sh qui est fourni) Le programme crée trois threads qui affichent 1000 fois respectivement "Hello", "World" et "and Everybody". Que pouvez-vous dire à propos de l’ordre de l’affichage ?Expliquer. Que pouvez-vous dire à propos du nombre d’affichages ? Expliquer. Quel affichage voyez-vous toujours ? Expliquer. Miage3, 2006-2007 4 Le programme utilise le héritage de Thread pour coder les threads. Changer le code pour utiliser l’interface Runnable. Changer également la classe pour la placer dans un paquetage exemple1. Réexécuter. 3.3 exempleThread2.java Compiler et exécuter plusieurs fois le programme exempleThread2. Voyezvous tous les affichages ? Essayez d’augmenter les valeurs d’attente (le arguments passés lors de la création des threads et utilisés pour les appels à sleep). Si vous mettez de trop grandes valeurs, vous risquez de ne plus voir aucun affichage. Pourquoi ? Changer la classe pour la placer dans un paquetage exemple2. 3.4 exempleThread3.java Dans ce programme, nous rajoutons la fonction join qui force le programme principal d’attendre la terminaison des threads. Compiler le programme et exécuter plusieurs fois. Voyez-vous tous les affichages ? Changer la classe pour la placer dans un paquetage exemple3. 3.5 exempleThread4.java Dans ce programme, nous manipulons une variable partagée Tableau. Les threads de ThreadDeposer incrémentent les valeurs du tableau, alors que les threads ThreadRetirer décrementent ces valeurs. Logiquement, à la fin les valeurs doivent être égales à 0 puisque les threads incrémentant et décrementant s’annulent. Compiler et exécuter plusieurs fois le programme. Y a-t-il des cas où le résultat est différent ? Expliquer. Modifier le programme pour utiliser l’interface Runnable. 3.6 exempleThread5.java Pour corriger le problème dans l’exemple précédent, on définit les deux méthodes incTab et decTab en tant que synchronized. Compiler et exécuter le programme. Quelles sont maintenant les valeurs observées ? Que remarquez vous au niveau du temps d’exécution’ Expliquer. Miage3, 2006-2007 3.7 5 exempleThread4.java Modifier l’exemple pour que la variable partagée soit un compte et non un tableau. Les opérations seront débiter, créditer et consulter. Est-ce que votre solde est égal à 0 à la fin ?