Mastel ASR\RESYD
Programmation Distribuée
2017-2018
Université A.Mira de Béjain
Faculté des Sciences Exactes
Département d"Tnformatique
Les Threads en Java
1, Définition
En Java, un thread est un objet d’une classe qui dispose d’une méthode nommée run qui sera
exécutée lorsque le thread sera démarré.
2. Création
Tl existe deux fagons pour créer un thread en Java. L’une consiste a instancier une classe dérivée
de la classe Thread, l'autre repose sur I’instanciation d’une classe spéciale, appelée Runnable.
Exemple:
Premigre méthode Deuxiéme méthode
Public class WyThroad extends
public void run) (
for (int i=1; i<-L0; i
Systen.out.printin (i);
1
Public class MyRunnab
public static void main(String
inplenents Runnable
Tal
unnable tl = new
MyRunnab)
public static void main(Strin
MyPhread ¢ = new MyThread(); public void run
testart 07 for
void start (): la JVM appelle la méthode run() systen.ot
du thread*/ )
}
Remarques
= Les opérations que vous souhaitez effectuer dans une autre pile d'exécution sont a placer dans la
méthode run), quiil s‘agisse d'une classe héritant de Thread ou d'une implémentation de
Runnable.
- Un programme comporte toujours au moins un thread dit "thread principal" correspondant tout
simplement 4 la méthode main.
java.lang. Runnable
effet, on peut implémenter
autant d'interfaces que lon
souhaite.
‘Avantages Tnconvénients
extends Chaque thread @ ses données [On ne peut plus hériter dune
| java.lang.Thread qui lui sont propres autre classe
Implements Lihéritage reste possible. En | Les attributs de votre classe
sont partagés pour tous les
threads qui y sont basés. Dans
certains cas, il peut s'avérer
gue cela soit un atout.3. La classe Thread
La classe Thread est définie dans le package java. ang. Elle implémente l'interface Runnable.
3.1. Construeteurs
La classe Thread peut posséder plusieurs constructeurs : un constructeur par défaut et plusieurs
autres
public Thread(); // crée un nouveau Thread dont le nom est généré automatiquement
(aléatoirement),
‘public Thread(Runnable target); // target est le nom de T'objet dont la méthode run est
utilisée pour lancer le Thread.
«public Thread(Runnable target, String name); // on précise l'objet et le nom du Thread.
«public Thread(String name); // on précise le nom du Thread
3.2. Méthodes
La classe Thread fournit des méthodes pour gérer les objets Thread : les créer, changer leur
priorité définie entre un minimum et un maximum avec une valeur moyenne par défaut, On peut
attribuer un nom & un thread, le démarrer, ’interrompre, le détruire, le mettre en attente pendant un
nombre de millisecondes, etc.
‘static int MAX_PRIORITY : priorité maximale.
« static int MIN_PRIORITY : priorité minimale
* static int NORM_PRIORITY : priorité par défaut
‘void setName (String) : définit le nom du thread.
‘String getName (): fournit le nom du thread.
‘* int getPriority () : fournit la priorité du thread,
‘void setPriority (int) : change la priorité.
+ static Thread currentThread () : fournit une référence sur le thread courant.
‘static void sleep (long n) : le processus est suspendu pour n millisecondes,
‘static int activeCount : nombre de threads du groupe.
‘static int enumerate (Thread_] tabThread) : copie dans le tableau les références des threads actfs.
‘* void start () : la JVM appelle la méthode run() du thread.
# run (): appel de la méthode run() de lobjet.
+ suspend () : suspend le thread.
‘resume (): Ie thread redevient actif.
‘+ void destroy () : détruit le thread,
‘void join () : attend la fin du thread.
String toString () : fournit certaines des caractéristiques du thread.
Ete
Cours PDJ 2017/2018 2 Dr.N. BATTAT4, L'ordonnancement des threads
Llordre d'exécution est souvent aléatoire, car Java utilise un ordonnanceur. Vous devez savoir
que si vous utilisez plusieurs threads dans une application, ceux-ci ne s'exécutent pas toujours en méme
temps. fait, 'ordonnanceur gére les threads de fagon aléatoire : il va en faire tourner un pendant un.
certain temps, puis un autre, puis revenir au premier, etc., jusqu’a ce qu'ils soient terminés. Lorsque
Yordonnanceur passe d'un thread 4 un autre, le thread interrompu est mis en sommeil tandis que l'autre
est en éveil,
L’ordonnancement dépend en fait aussi bien de l'implémentation de la JVM que du systéme
exploitation sous-jacent. II y a deux modéles principaux concernant la JVM, Dans le modéle "green
thread", c'est la JVM qui implémente l'ordonnancement des threads qui lui sont associés. Dans le
modéle "threads natifs", c'est le systéme exploitation hte de la JVM qui effectue 'ordonnancement
des threads JAVA.
Cours PDJ 2017/2018 3 Dr.N, BATTAT5. Sommeil d'un thread
« static void sleep (long n) : le processus est suspendu pour.
Cet appel demande que le Thread correspondant soit arrété (on dira "mis en sommeil") pour
au moins la durée mentionnée (n millisecondes). Cette démarche laisse ainsi la possibilité 4 d’autres
threads de s’exécuter a leur tour. La méthode sleep est susceptible de générer une exception de type
InterruptedException
Exemple :
Public class TSeinel
{ public static void main (String args{])
{ Berit el = new Berit ("bonjour ", 10, 5)
Ecrit 2 = new Ecrit e", 12, 10) ¢
23 = new Ecrit 15);
el.start()
rt ()
e3.start() ;
}
)
class Ecrit extends Thread
{ public Ecrit (String texte, int nb, long atte:
texte ; this.nb = nb;
attente ;
,
public void run ()
( try
{ for (int i-0 7 icnb 7 itt)
{ System.out.print (texte) ;
sleep (attente) ;
,
}
catch uptedException e) {} // Impose par sleep
}
private String texte ;
private int nb;
private long attente ;
,
Le résultat de Pexécution =
bonjour b
bonjour b onjour
bonjour b bonjour bonjour
bonsoir b onjour bonsoir b
bonjour b
bonsoir b onsoir
Cours PDJ 2017/2018 3 Dr.N, BATTAT6. Priorités des threads
La méthode sleep() permet d'endormir un Thread au profit d'un autre. Il existe un autre moyen
de gérer le passage du contréle d'un Thread & un autre: & chaque Thread de Java est associée une
priorité c'est & dire une valeur numérique qui permet de comparer l'importance de deux Threads et de
donner une préférence d'exécution & lun ou & l'autre.
«static int MAX_PRIORITY: priorité maximale.
«static int MIN_PRIORITY: priorité minimale.
«static int NORM_PRIORITY : priorité par défaut.
int getPriority () : fournit la priorité du thread.
«void setPriority (int) : change la priorité,
Exemple :
public class TestThreadi0 (
public static void main(string{] args) {
ystem,out.printin("Thread.MIN_ PRIORITY = " + Thread.MIN_PRIORTTY) ;
system. out.printin("Thread.NORW PRIORITY = " + Thread. NORM ,
ystem.out.printin("Thread.MAX_ PRIORITY = " + Thread.MAX_ PRIORITY) ;
,
1
Thread
Thre
Thread
Le résultat de Pexéeution:
MIN_PRIORITY = 1
NORM_PRIORITY =
MAX PRIORITY = 10
Cours PDJ 2017/2018 5 Dr.N, BATTATLorsqu'un Thread est créé, il hérite de la priorité du Thread qui le erée. Cette priorité peut étre
modifige en utilisant la méthode setPriority(int) en donnant une valeur entre MIN_PRIORITY et
MAX_PRIORITY (constantes définies dans la classe Thread). Pour des Thread candidats a I'exécution
ayant la méme priorité, JAVA fait tourer le droit d'exécution d'un Thread a l'autre dés que ce dr
est libéré et condition quil n'y ait pas un Thread de priorité supérieure. La priorité est principalement
utilisée pour gérer 'efficacité d'une application
Exemple :
public class
Ant nb;
public PrintNb (int nb) {
this.nb = nb;
}
public void run()
ntNb implements Aunnableq
System. out.printla();
for (int i=0;i<10;i#+)
system. out.print (nb);
,
}
public class Nonbres {
public static void main(string{] args 1(
Thread nbl,nb2, nb3;
nbi= new Thread (new PrintNb(1)); nbl.start ();
bl. sey (Thread. MN PRIORITY);
nb?" new Thread(new PrintNb(2)); nb2.start ();
nb2.se} (Thread. Max PRIORITY) ;
no3~ new Thread (new PrintNb(3)); np3.start ()7
jority ( Thread. tiokit
,
)
Le résultat d’exécution :
2222222222
3333333333
qiiliiiiin
Cours PDJ 2017/2018 6 Dr.N, BATTATUn Thread donné peut, & tout moment, renoncer a son droit d'exécution en appelant la méthode
yield(). Contrairement sleep(long), ce renoncement n'est pas une mise en sommeil pour une durée
fixée au profit de tous les Threads, mais seulement un passage temporaire du contrdle aux autres
Threads de méme priorité,
Notons que yield() n'émet pas d'exceptions, nous n'avons done pas beso’
de lentourer d'une
close wry & catch.
Exemple :
Glass Vielathread extends Thread
public void run() {
for (int count = 0; count < 4; co!
system. ovt.print
yield()
n( count + "Pron: "= getName() );
class TestYield
public static void main(
Yieldthread first
YieldThread
Cours PDJ 2017/2018 4 Dr. N, BATTAT7. Interruption d’un thread
Les threads s'achevaient tout naturellement avec la fin de "exécution de leur méthode run (qui
se produisait aprés un nombre déterminé d’appels de sleep). Dans certains cas, on peut avoir besoin
interrompre prématurément un thread depuis un autre thread. Ce besoin peut devenir fondamental
dans le cas de ce que nous nommerons des "*hreads infinis", c’est-d-dire dans lesquels la méthode run
n’a pas de fin programmée; ce pourrait étre le cas d’un thread de surveillance d’appels dans un serveur
Web.
Java dispose d’un mécanisme permettant 4 un thread d’en interrompre un autre. La méthode
interrupt de la classe Thread demande a l’environnement de positionner un indicateur signalant une
demande d’arrét du thread concemé.
Par ailleurs, dans un thread, il est possible de connaitre I’état de cet indicateur & ’aide de la
méthode statique interrupted (il existe également isInterrupted).
Ce schéma récapitule la situation :
Thread 1 Thread 2 nommé t
tinterrupt() ; // positionne un indicateur dans t
if (interrupted)
foe
return ; // fin du thread
}
Notez bien que l’arrét effectif du thread 1 reste sous sa propre responsabilité. Rien n’empéche
(hormis le bon sens) de faire autre chose que return, voire méme d’ignorer cette demande d’arrét.
D’autte part, il est nécessaire que le test de lindicateur se fasse réguligrement dans la méthode run et
non simplement au début de son exécution.
Cours PDJ 2017/2018 8g Dr.N, BATTAT8. Coordination de threads
Dans certains cas, il faudra éviter que deux threads puis
ent accéder (presque) en méme temps
au méme objet. Ou encore, un thread devra attendre qu’un autre ait achevé un certain travail sur un
objet avant de pouvoir lui-méme poursuivre son exécution,
Le premier probléme est réglé par l'emploi de méthodes mutuellement exclusives qu’on
appelle souvent, un peu abusivement, "méthodes synchronisées", en faisant référence a la fagon de les
déclarer avec le mot-clé synchronized. A un instant donné, une seule méthode ainsi déclarée peut étre
appelée pour un objet donné.
Exemple :
Public class Compte {
private int solde = 0;
public synchronized void ajouter(int somme) {
solde
sprint (" ajo
System.o
public synchronized void retirer(int sone) {
solde -= somme;
em. out .print ("
re " + somme);
public synchronized void
solde += somme;
perationNulle(int some)
sprint (" ajou somme) :
eprint (" re " + some);
public synchronized int getSolde() {
return solde;
’
public class Operation extends Thread
private Compte compte;
public Operation
super (non) ;
this.compte = compte;
ng nom, Compte compte) {
public void
while (true)
int i= (int) (Math.x:
String nom = getNane();
system. out.print (nom) ;
0
compte operationMulle (i) ;
int solde = compte.getSolde();
system. out.peint (nom) ;
if (solde != 0) nom + ":*¥solde="
Cours PDJ 2017/2018 9
Dr. N. BATTATpublic static void main (strii
Compte compte
for (int i
new Compte ();
A < 207 dn)
= new operation("™
+ (char) (1A' + i), compte);
Cours PDJ 2017/2018
10
Dr. N. BATTATLe second probléme sera réglé par des mécanismes d’attente et de notification mis en ceuvre a
Paide des méthodes wait et notty
Remarque : notifyAll): ressemble a notify avec la différence qu'il réveille tous les threads qui était
en attente au moment de son exéc
* Tri d'un tableau d'e:
* Utilisation de wait() et de join()
/
public class Trieur extends Thread
private int{) ty // tableau a trier
private int debut, fin; // tranche de ce tableau qu'il faut
trier
private Trieur parent; // tread Trieur qui a lancé ce (this)
private int nbNotify = 0; // Nombre de notifys envoyés 4
(this) Trier
public Trieur(int{]
this (null, t, 0,
public Trieur(Trieur parent, int{] t, int debut, int fin)
this.parent rent;
this.t = ty
this.debut = debut;
this.fin = fin;
start();
public synchronized void notifier() {
// Notifie tous les threads en attente sur "ce" (this)
// Attention, quand le message sera envoyé au parent (dans
run()),
// on incrémentera la variable nbNotify du par
t (qui sera le
// implicite) et on notifiera le parent.
// On peut aussi ne pas utiliser de méthode mais dans ce cas,
L fa
// écrire parent.nbNotifyt+; parent.notifyAll(); dans un bloc
// synchronisé sur parent placé dans la méthode run.
public void run() {
if (fin - debut < 2) {
if (t{debut] > t[fin}) {
echanger (debut, fin);
Cours PDJ 2017/2018 u Dr. N. BATTAT?
)
int milieu = debut + (fin - debut) / 2;
trieurl = new Trieur(this, t, debut, milieu);
ieur2 = new Trieur(this, t, milieu + 1, fin);
/ attend les 2 threads
synchronized(this) {
ue 2 notifications n'ont pas été recues (1 par
// trieur "fils"), on attend.
while (nbNotify < 2) {
wait):
)
)
catch (InterruptedException e) {}
}
iFusion (debut, fin);
)
if (pare null) {
parent.notifier(); //
Ltattend
)
yee
* Echanger tli] et tli
private void echanger(int i, int 3) {
int valeur = tli];
tli] = tty)
t{j] = valeur;
ye
* Fusionne 2 tranches déja triées du tableau t.
* = lére tranche : de debut a milieu
* = 2ame tranche : de milieu + 1 a fin
* @param milieu indique le dernier indice de la 1ére tranche
private void trifusion(int debut, int fin) {
// tableau ob va aller la fusion
] tFusion = new int[fin - debu
milieu = (debut + fin) / 2
// Indices des éléments & comparer
2 = milieu + 1
// indice de 1
iFusion = 0;
le (il <= milieu &&@ i2 <= fin) {
(eli) < tli2n ¢
he
prochaine case du tableau tFusion A remplir
tFusion[iFusion++] = tlilt+l;
)
else {
tFusion[iFusion++] = t{i2++];
)
Cours PDJ 2017/2018 12 Dr. N. BATTAT// la 2éme tranche
for (int i= ily i
‘Fusion |iFusion++
)
}
// Copie tFusion dans t
for (int i= 0, j = debut; i <
tjtt] = tFusion[it+];
}
iag(]
public static void main(s
(1 t = {5, 8 3, 2, 7, 10,
eur trie new Trieur(t};
yf
rieur.join();
,
ch (Interruptedzxception e)
i 10; ins) {
out.printIn("" 4 i);
Cours PDJ 2017/2018 15 Dr. N. BATTAT