Vous êtes sur la page 1sur 6

Dév. d’applications réparties 2020/2021.

Semestre 1 Université Constantine 2

Université Abdelhamid Mehri – Constantine 2


2020/2021. Semestre 1

DÉVELOPPEMENT D’APPLICATIONS REPARTIES

– Cours 3 –
Chapitre 02 : La programmation concurrente avec les
Threads
L’API Thread en Java

Staff pédagogique
Nom Grade Faculté/Institut Adresse e-mail
Dr. KITOUNI Ilham MC-A Nouvelles technologies ilham.kitouni@univ-constantine2.dz
Dr. MENNOUR Rostom MC-B Nouvelles technologies rostom.mennour@univ-constantine2.dz

Étudiants concernés
Faculté/Institut Département Niveau spécialité
Nouvelles technologies IFA Master 1 RSD

Objectifs du cours 3
Connaitre l’utilité des threads.
Savoir les méthode de créer un thread en java.
Voir quelque méthode utile pour gérer les threads en java.

© Dr. KITOUNI Ilham & Dr. MENNOUR Rostom Page 1 sur 4


Dév. d’applications réparties 2020/2021. Semestre 1 Université Constantine 2

Utiliser les concepts de l’orienté objet.

© Dr. KITOUNI Ilham & Dr. MENNOUR Rostom Page 2 sur 4


Dév. d’applications réparties 2020/2021. Semestre 1 Université Constantine 2

1 Utilisation de la classe Thread


Dans le dernier chapitre, nous avons considéré les threads comme des tâches distinctes exécutées en
parallèle. Ces tâches sont simplement du code exécuté par le thread, et ce code fait en réalité partie de
notre programme. Le code peut télécharger une image à partir du serveur ou lire un fichier audio sur
les haut-parleurs ou toute autre tâche. Parce que c’est du code, il peut être exécuté par notre thread
d’origine. Pour introduire le parallélisme que nous désirons, nous devons créer un nouveau thread et
faire en sorte que le nouveau thread exécute le code approprié.

Commençons par examiner l’exécution d’un seul thread dans l’exemple suivant:
1 public class NotreClasse {
2 public void run () {
3 for ( int I = 0; I < 100; I ++) {
4 System . out . println ( " Hello " ) ;
5 }
6 }
7 }

Dans cet exemple, nous avons une classe appelée NotreClasse. La classe NotreClasse a une seule
méthode publique appelée run () qui écrit simplement une chaı̂ne 100 fois sur la console Java ou sur la
sortie standard. Si nous exécutons ce code à partir d’un programme java, comme indiqué ci-dessous,
il s’exécute dans le thread du programme :
1 public class NotrePgm {
2 public static void main () {
3 NotreClasse nc = new NotreClasse () ;
4 nc . run () ;
5 }
6 }

Si nous instancions un objet NotreClasse et appelons sa méthode run (), rien d’inhabituel ne se pro-
duit. Un objet est créé, sa méthode run () est appelée et le message ”Hello” est imprimé 100 fois.
Tout comme les autres appels de méthode, l’appelant de la méthode run () attend que la méthode run
() se termine avant de continuer.

Que faire si nous voulons que la méthode run () de NotreClasse s’exécute en parallèle avec main () et
d’autres méthodes du programme principal ? Pour ce faire, nous devons modifier la classe NotreClasse
afin qu’elle puisse être exécutée par un nouveau thread. Nous allons donc commencer par faire hériter
NotreClasse de la classe Thread (java.lang.Thread) :
1 public class NotreClasse extends Thread {
2 public void run () {
3 for ( int I = 0; I < 100; I ++) {
4 System . out . println ( " Hello " ) ;
5 }
6 }
7 }

Si nous compilons ce code et l’exécutons avec notre programme principal, tout fonctionne exactement
comme avant: la méthode main () du programme appelle la méthode run () de l’objet NotreClasse
et attend que la méthode run () soit renvoyée avant de continuer. Le fait que cet exemple compile et
s’exécute prouve que la classe Thread existe. Cette classe est notre premier aperçu de l’API de thread
en Java et constitue l’interface de programmation permettant de démarrer et d’arrêter nos propres
threads. Mais nous n’avons pas encore créé de nouveau fil conducteur. nous avons simplement créé
une classe qui a une méthode run (). Pour continuer, modifions notre principal comme ceci :
1 public class NotrePgm {
2 public static void main () {
3 NotreClasse nc = new NotreClasse () ;
4 nc . start () ;
5 }

© Dr. KITOUNI Ilham & Dr. MENNOUR Rostom Page 1 sur 4


Dév. d’applications réparties 2020/2021. Semestre 1 Université Constantine 2

6 }

Dans cette deuxième version de notre principal, nous n’avons modifié qu’une ligne : l’appel de la
méthode run () est maintenant un appel de la méthode start (). La compilation et l’exécution de ce
code confirment qu’il fonctionne toujours et que l’utilisateur semble s’exécuter exactement de la même
manière que dans l’exemple précédent. Étant donné que la méthode start () ne fait pas partie de la
classe NotreClasse, nous pouvons en conclure que l’implémentation de la méthode start () fait partie
de la classe Thread ou de l’une de ses superclasses. De plus, le principal accomplissant toujours la
même tâche, nous pouvons en conclure que la méthode start () déclenche un appel, directement ou
indirectement, à la méthode run ().

À y regarder de plus près, ce nouveau principal se comporte différemment de la version précédente. S’il
est vrai que la méthode start () appelle finalement la méthode run (), elle le fait dans un autre thread.
La méthode start () est ce qui crée réellement un autre thread de contrôle; Ce nouveau fil, après avoir
traité quelques détails d’initialisation, appelle ensuite la méthode run (). Une fois la méthode run ()
terminée, ce nouveau thread traite également des détails de la terminaison du thread. La méthode
start () du thread d’origine retourne immédiatement. Ainsi, la méthode run () sera exécutée dans
le thread nouvellement formé à peu près au même moment où la méthode start () retourne dans le
premier thread.

Voici les méthodes de la classe Thread dont nous avons discuté jusqu’à présent:

Thread()
Construit un objet thread en utilisant les valeurs par défaut pour toutes les options.

void run ()
La méthode que le thread nouvellement créé va exécuter. Les développeurs doivent remplacer cette
méthode par le code dans lequel ils souhaitent que le nouveau thread s’exécute. nous montrerons un
peu plus loin l’implémentation par défaut de la méthode run (), mais il s’agit essentiellement d’une
méthode vide.

void start ()
Crée un nouveau thread et exécute la méthode run () définie dans cette classe de thread.

Pour réviser, créer un autre thread de contrôle est un processus en deux étapes. Tout d’abord, nous
devons créer le code qui s’exécute dans le nouveau thread en redéfinissant la méthode run () de notre
sous-classe. Ensuite, nous créons l’objet sous-classé actuel à l’aide de son constructeur (qui appelle le
constructeur par défaut de la classe Thread dans ce cas) et commençons l’exécution de sa méthode
run () en appelant la méthode start () de la sous-classe.

1.1 run () Vs main ()


En substance, la méthode run () peut être considérée comme la méthode main () du nouveau thread
formé : un nouveau thread commence l’exécution avec la méthode run () de la même manière qu’un
programme commence l’exécution avec la méthode main ().
Alors que la méthode main () reçoit ses arguments du paramètre argv (qui est généralement défini
à partir de la ligne de commande), le thread nouvellement créé doit recevoir ses arguments par pro-
gramme du thread d’origine. Par conséquent, les paramètres peuvent être transmis via le constructeur,
des variables d’instance statiques ou toute autre technique conçue par le développeur.

1.2 Mettre un thread en pause


Ce que nous n’avons pas vu jusqu’à présent, c’est l’appel à la méthode sleep () : static void sleep
(long milliseconds) : Met le thread en cours d’exécution en veille pendant le nombre de millisecondes

© Dr. KITOUNI Ilham & Dr. MENNOUR Rostom Page 2 sur 4


Dév. d’applications réparties 2020/2021. Semestre 1 Université Constantine 2

spécifié. Cette méthode est statique et est accessible via le nom de la classe Thread. static void sleep
(longues millisecondes, int nanosecondes) : Met le thread en cours d’exécution en veille pour le
nombre spécifié de millisecondes et de nanosecondes. Cette méthode est statique et est accessible via
le nom de la classe Thread.
Reprenons notre thread NotreClasse :
1 public class NotreClasse extends Thread {
2 public void run () {
3 for ( int I = 0; I < 100; I ++) {
4 System . out . println ( " Hello " ) ;
5 try {
6 sleep ( timediff ) ;
7 } catch ( Exception e ) {}
8 }
9 }
10 }

La méthode sleep () fait partie de la classe Thread et fait en sorte que le thread en cours (le thread
ayant effectué l’appel de la méthode sleep ()) s’interrompe pendant le délai spécifié, en millisecondes.
L’instruction try dans l’exemple de code est nécessaire en raison de certaines des exceptions émises
par la méthode sleep ().

1.3 Arrêter un thread


Les threads doivent toujours se terminer en revenant de leur méthode run (). C’est au développeur
de décider comment un thread devrait savoir quand il est temps de revenir de la méthode run (); La
mise en place d’un drapeau (flag), est généralement la méthode la plus simple.

Définir un drapeau signifie que mon thread doit vérifier le drapeau périodiquement. N’y a-t-il pas un
moyen plus propre d’arrêter le fil? Et n’y a-t-il pas moyen de terminer le fil immédiatement plutôt
que d’attendre qu’il vérifie un drapeau ? Eh bien oui et non. La classe Thread contient une méthode
stop () qui vous permet d’arrêter un thread immédiatement: peu importe ce que fait le thread, il
sera terminé. Cependant, la méthode stop () est très dangereuse. En Java 2, la méthode stop () est
obsolète. Cependant, les raisons qui l’ont conduit à devenir obsolète existent réellement dans toutes
les versions de Java. Vous devez donc éviter d’utiliser la méthode stop () dans toutes les versions de
Java.

2 Utilisation de l’interface Runnable


Aussi simple que cela soit de créer un autre thread de contrôle, il existe un problème avec la technique
décrite précédemment. Cela est dû au fait que les classes Java ne peuvent hériter de leur comportement
que d’une seule classe, ce qui signifie que l’héritage peut être considéré comme une ressource rare et
qu’il est donc ”coûteux” pour le développeur.
Dans notre exemple, nous enfilons une simple boucle, ce n’est donc pas un problème. Cependant,
si nous avons une structure de classe complète qui a déjà une arborescence d’héritage détaillée et
que nous souhaitons qu’elle s’exécute dans son propre thread, nous ne pouvons pas simplement faire
en sorte que cette structure de classe hérite de la classe Thread comme nous le faisions auparavant.
Une solution serait de créer une nouvelle classe héritant de Thread et contenant des références aux
instances des classes dont nous avons besoin. Ce niveau d’indirection est une gêne.
Le langage Java résout ce problème d’héritage multiple en utilisant le mécanisme appelé interfaces.
Ce mécanisme est pris en charge par la classe Thread et signifie simplement qu’au lieu d’hériter de la
classe Thread, nous pouvons implémenter l’interface Runnable (java.lang.Runnable), qui est définie
comme suit:
1 public interface Runnable {
2 public abstract void run () ;
3 }

© Dr. KITOUNI Ilham & Dr. MENNOUR Rostom Page 3 sur 4


Dév. d’applications réparties 2020/2021. Semestre 1 Université Constantine 2

L’interface Runnable contient une seule méthode: la méthode run (). La classe Thread implémente
réellement l’interface Runnable; par conséquent, lorsque vous héritez de la classe Thread, votre
sous-classe implémente également l’interface Runnable. Cependant, dans ce cas, nous souhaitons
implémenter l’interface Runnable sans hériter réellement de la classe Thread. Ceci est réalisé en rem-
plaçant simplement l’expression ”implémente Runnable” par l’expression ”extend Thread”; aucune
autre modification n’est nécessaire à l’étape 1 de notre processus de création de thread :
1 public class NotreClasse implements Runnable {
2 public void run () {
3 for ( int I = 0; I < 100; I ++) {
4 System . out . println ( " Hello , from another thread " ) ;
5 }
6 }
7 }

L’étape 2 de notre processus de création de threads comporte d’autres modifications. Puisqu’une


instance de la classe NotreClasse n’est plus un objet Thread, elle ne peut pas être traitée comme
tel. Donc, afin de créer un thread de contrôle séparé, une instance de la classe Thread est toujours
nécessaire, mais elle sera instanciée avec une référence à notre objet NotreClasse. En d’autres termes,
son utilisation est légèrement plus compliquée :
1 public class NotrePgm {
2 public static void main () {
3 NotreClasse nc = new NotreClasse () ;
4 Thread th = new Thread ( nc ) ;
5 th . start () ;
6 }
7 }

Comme auparavant, nous devons créer une instance de la classe NotreClasse. Cependant, dans cette
nouvelle version, nous devons également créer un objet thread réel. Nous créons cet objet en passant
notre référence d’objet NotreClasse exécutable au constructeur du thread en utilisant un nouveau
constructeur de la classe Thread :
1 Thread ( Runnable target )

Construit un nouvel objet thread associé à l’objet Runnable donné.

La méthode start () du nouvel objet Thread est appelée pour commencer l’exécution du nouveau
thread de contrôle.

© Dr. KITOUNI Ilham & Dr. MENNOUR Rostom Page 4 sur 4

Vous aimerez peut-être aussi