Вы находитесь на странице: 1из 5

Bonjour à tous, dans cette séquence nous allons parler de la classe Thread

la classe Thread c'est l'objet de base permettant le parallélisme en Java


et vous trouverez partout dans les langages
une notion équivalente par exemple
le type Task en ADA
ou dans des bibliothèques de....
programmation par exemple POSIX ou autres
également un type qui est associé à ce mécanisme système
et en fait
cet objet
de base dispose d'un certain nombre de primitives
les plus importantes c'est start(), sleep(), yield(), wait(), notify()
et notifyAll() que nous verrons plus tard
alors au départ on a vu dans une séquence précédent le cycle de vie
d'un flux d'exécution et donc on va regarder un petit peu ce qui se passe
avec Thread
Thread c'est une classe mais elle a un rôle un petit peu particulier c'est que
quand je
crée une occurrence
de cette classe
je vais créer en fait une nouvelle
Thread donc un nouveau flux d'exécution
évidemment
il va falloir que je lui associe
quelque chose
qui va s'exécuter
donc lorsque la Thread est créée
et bien la méthode start() va la mettre dans l'état prêt donc
il y a deux choses il y a le fait que l'objet soit créé
et le fait que l'objet puisse envisager d'avoir le processeur
donc une fois que vous avez fait un start() il est prêt
ça veut pas dire qu'il s'exécute tout de suite ça peut attendre un petit moment en
fonction des
exécutions qui sont en cours
alors à ce moment-là vous allez avoir le système classique
où l'objet va être
élu, avoir le processeur
et sur fin de quantum
vous avez cette boucle qu'on a déjà vue
lorsque j'ai parlé des flux d'exécutions c'est assez classique
et puis
l'objet peut également se trouver suspendu et en particulier
les méthodes
comme sleep(), wait()
peuvent provoquer la suspension
de l'objet
et à ce moment-là
et bien il y a d'autres méthodes qui vont le remettre dans un état prêt
donc typiquement notify(), notifyAll(), on les verra
un peu plus tard
il y a également yield()
yield() en fait il passe pas par l'état suspendu mais il dit j'abandonne le
processeur
donc en fait je me remets dans la file d'attente
bon si je suis tout seul évidemment je reprends derrière
mais c'est une manière de provoquer ce qu'on appelle une commutation
donc si j'étais élu et bien je provoque l'exécution potentielle
d'une autre Thread
et moi je me remets prêt je suis pas suspendu parce que suspendu
je ne suis pas éligible pour avoir
le processeur
tandis que prêt
je suis éligible pour le réavoir éventuellement immédiatement si c'est possible
et puis au bout d'un certain temps
la fin de l'exécution amène la Thread dans un état où elle est terminée
alors bien évidemment que se passe-t-il pendant que on fait tout cela et bien
on est en train d'exécuter du code
et ce code se situe dans une méthode qui
doit être implémentée
qui s'appelle run(), alors vous pouvez enfin je dis elle doit être implanté mais
vous pouvez
ne pas l'implémenter
mais cette méthode sera appelée par start() quoi qu'il arrive et
l'implémentation par défaut de la classe Thread c'est je ne fais rien donc si je
fais
euh...je crée une Thread
sans avoir
implémenté
la méthode run(), on va voir comment on peut implémenter la méthode run()
et bien évidemment ça va pas marcher, ça va pas le faire
prenons un exemple simple donc
on va faire des petites tâches qui font pas grand-chose
donc vous voyez que
la manière d'associer un traitement à la méthode run()
c'est bien évidemment la première manière parce qu'il y a plusieurs façons
de manipuler les Thread on verra qu'il y a des façons qui sont plus
normales que d'autres
donc on voit cette première manière
c'est d'étendre
la classe Thread
donc je vais créer ici
une classe uneTache
qui va étendre Thread
donc je rajoute
euh...un attribut dédié
à cette classe
et puis ici
je vais avoir
le constructeur qui va me permettre d'initialiser la Thread
je n'utilise pas le constructeur de la super classe
et puis la méthode run() qui se contente de dire bonjour au revoir
en utilisant le nom qui a été spécificité ici
et puis j'ai la classe principale
de mon exemple
qui contient la seule méthode main
je vais créer
trois occurrences de uneTache
et puis je vais
les lancers et
regardons ce que cela donne
alors ce qui se passe c'est que là
je vous donne plusieurs exécutions
ces exécutions elles diffèrent vous voyez que ici c'est t1 qui démarre qui
s'arrête puis t3 dit "Bonjour", se suspens et dit "Au revoir" là derrière et le
"Bonjour" et
le "Au revoir" de t3
sont séparés
par un "Bonjour" et "Au revoir" de t2 et puis la deuxième exécution
c'est t1, t3, t2 comme ça et puis la 3ème exécution c'est t2, t1, t3
qui passe
donc
je vous ai parlé d'indéterminisme il se passe plein de choses bien évidemment
ça se passe au niveau du langage assemblage donc
euh...mais là ce qu'on voit c'est que
rien qu'entre mes deux instructions je peux avoir une commutation
et vous voyez que deux exécutions peuvent ne pas donner
la même chose c'est parfaitement normal
on est dans un contexte concurrent
t1, t2 et t3 s'exécutent en concurrence les uns avec les autres
on va construire
notre premier chronogramme donc
on a vu dans une séquence précédente ce qu'était un chronogramme là
je vais le construire je vais pas le dessiner à la main parce que vous avez vu que
j'étais
assez...
pathétique
en termes de dessin à la main
et donc en fait regardons ici le chronogramme qui a été préparé donc là
je lance mon programme qui lance donc la classe principale
et la classe principale je vais avoir
une partie là le trait c'est ce qui s'exécute et les pointillés c'est ce qui ne
s'exécute pas
donc
que fait mon programme principale il commence d'abord à faire des new
donc il crée
dans un premier temps la Thread t1
puis la Thread t2
puis la Thread t3
pour l'instant les Thread sont créées, l'exécution n'a pas eu lieu vous voyez que
la
création se passe en 2 temps
création de l'objet et pour que l'exécution commence pour une Thread
il faut lancer start()
donc là j'ai un t1.start() donc vous le voyez apparaître ici
c'est le démarrage
puis un t2.start() puis un t3.start() alors je les ai pas
représentés avec un aller-retour
parce que là ici c'est vraiment un lancement d'exécution et
je vous rappelle que je me mets dans l'hypothèse
où j'ai
un seul cœur donc en fait pendant que le main s'exécute
donc ça c'est un flux qui existe toujours
et bien les autres ne peuvent pas s'exécuter
donc
une fois que cela c'est terminé
et bien la classe principale a terminé son exécution pour autant
le programme n'est pas terminé puisque j'ai les Threads
qui s'exécutent et le programme ne sera terminé que lorsque tous les flux
d'exécution
toutes les Threads
se seront terminées donc
bah que se passe-t-il
là ici c'est t2 qui démarre donc je vois "Bonjour de t2", "Au revoir de t2"
j'imagine qu'il
n'y a pas de commutation
ici maintenant c'est t1 qui prend la relève
"Bonjour de t1", "Au revoir de t1"
et ensuite c'est t3
qui s'exécute : "Bonjour de t3", "Au revoir de t3"
et vous remarquez que à la fin de chaque séquence
et bien ces Threads n'ont plus d'instructions à exécuter donc ici
t2 se termine
t2
t1 se termine
t3 se termine, c'est simple
lorsque les trois Threads sont terminées
et bien là mon programme est réellement terminé
et vous voyez que ce programme il a 4
flux d'exécution
parce que il y a le main
puis les trois flux d'exécution qui ont été créés par le main
toujours considérer
la classe principale, l'exécution de la classe principale
comme un flux
à part entière
alors que se passe-t-il quand le programme est terminé et bien en fait
le processus parce que tout ça ça s'exécute dans un processus
souvenez-vous de ce qu'on a dit dans une séquence passée
et bien est nettoyé par le système d'exploitation
donc là je vais vous proposer une petite variation pour laquelle on va forcer
des commutations de tâche
donc c'est ce que j'ai fait en introduisant ici l'instruction
"Thread.yield()" d'accord
yield() ce qu'il va faire c'est qu'il va provoquer une commutation donc avant
j'avais des exécutions qui pouvait avoir une commutation ou qui pouvait ne pas
l'avoir
là je l'aurai forcément
et donc je vais avoir un peu plus de commutations
donc
ça va donner ceci
du coup vous voyez que j'ai des "Bonjour" qui se séparent des "Au revoir"
mais ils s'entrelacent également
de façon variable comme c'était le cas auparavant et donc j'ai toujours cette
propriété que deux exécutions ne vont pas forcément
être identique
maintenant regardons le chronogramme
pour cette variation donc
jusqu'à présent pas de souci je lance
mon exemple
et là et bien
création de
la Thread t1
plus de la Thread t2
puis de la Thread t3
puis j'exécute
les trois start()
et ensuite
le programme principal se termine
donc maintenant regardons l'exécution des programmes associés
donc là je vais avoir un "Bonjour" de t1
et puis il va y avoir une commutation qui va se passer
elle est quelque part, j'aurais pu mettre un petit éclair, elle est quelque part
forcée par l'exécution du yield() qui est ici
donc et puis c'est t1 là qui a démarré
t3 qui prend la relève
t2 qui prend la relève
maintenant
ben c'est l’ordonnanceur hein, c'est l'exécution moi j'ai lancé le programme et
puis après j'ai reconstitué
t3 reprend la main vous voyez que c'est pas parce que t1 s'est exécuté que c'est
lui qui
va reprendre la main
on sait pas
t3 reprend la main et là le programme se terminer puisqu'on arrive à la fin
de la méthode run()
là après c'est t1 qui reprend la main et enfin
c'est t2 qui prend la main à chaque fois les Threads se terminent et ici
comme auparavant
le programme
est terminé et
le processus disparaît
alors que dire en guise de conclusion
ben vous voyez que
c'est quand même extrêmement simple cette première manière de procéder
je vais créer des fils d'exécution en dérivant la classe Thread et en surchargeant
la méthode run() avec les traitements que moi je veux avoir
et à chaque fois que je vais vouloir créer un nouveau traitement de ce type
et bien je vais créer un objet de cette classe dérivée
et puis je vais le lancer avec le start(), il ne suffit pas de le créer il faut
aussi le lancer
et puis voilà
alors bien évidemment on n'a pas encore vu les communications ça c'est quelque
chose
qu'on verra plus tard mais on a déjà une forme de communication parce que si
j'ai 2 classes différentes
Thread1 et Thread2 par exemple client et serveur
et bien le client pourra appeler une méthode
de la classe serveur et à ce moment-là
vous allez pouvoir déjà avoir
un début de semblant de communication mais on va rentrer en détail plus
tard sur les problèmes de communication
qui sont évidemment beaucoup plus compliqués que cela
voilà
je vous remercie de votre attention, à bientôt

Вам также может понравиться