POO – JAVA
Threads
Y. I. KHAMLICHI
THREADS
2
Multi-tâches
Multi-tâches : exécution de plusieurs processus
simultanément.
Un processus est un programme en cours d'exécution.
Le système d’exploitation distribue le temps CPU entre les
processus
Un processus peut être dans différents états.
En exécution (running) : il utilise le processeur
Prêt : le processus est prêt à s'exécuter, mais n'a pas le
processeur (occupé par un autre processus en exécution)
Bloqué
3
Y. I. KHAMLICHI
Parallélisme
Parallélisme : pouvoir faire exécuter plusieurs tâches à
un ordinateur avec plusieurs processeurs.
Si l’ordinateur possède moins de processeurs que de
processus à exécuter :
division du temps d’utilisation du processeur en tranches
de temps (Time Slice en anglais)
attribution des tranches de temps à chacune des tâches de
façon telle qu’on ait l’impression que les tâches se
déroulent en parallèle.
on parle de pseudo-parallélisme
Les systèmes d’exploitation modernes gèrent le muti-
tâches et le parallélisme
4
Y. I. KHAMLICHI
MULTITÂCHE,
PROCESSUS ET THREAD
• Un thread (tâche en français, appelé aussi processus léger ou
activité) est un fil d’instructions (ou fil d’exécution) à l’intérieur
d’un processus,
• Un thread est un sous-processus qui exécute une série d’instructions
d’un programme donné.
• Les programmes qui utilisent plusieurs threads sont dits
multithreadés.
• Processus est un programme qui s’exécute et qui possède son
propre espace mémoire.
• Thread est un processus qui fonctionne comme un S.E. en lançant
des sous-tâches internes au processus (multi-programmation). Ces
sous-tâches sont nommées « flux d’exécution » ou Threads.
• Multithreading : Windows, Solaris, MacOs, … supportent
l’utilisation d’application contenant des threads
5
MULTITÂCHE,
PROCESSUS ET THREAD
6
MULTITÂCHE,
PROCESSUS ET THREAD
Exemple d’un schéma qui illustre les temps d'exécution et de latence des
threads.
7
INTERFACE GRAPHIQUE :
MULTITÂCHE
En Java le multithreading signifie qu'il faut
1. Créer un thread,
2. Ecrire la tâche exécutée par le thread,
3. Lier la tâche au thread.
Pour réaliser cela, il faut étudier et comprendre la classe
Thread.
8
Création
La classe [Link] permet de créer de nouveaux
threads
Un thread doit implémenter obligatoirement l’interface
Runnable
le code exécuté se situe dans sa méthode run()
2 méthodes pour créer un Thread :
1) une classe qui dérive de [Link]
• [Link] implémente Runnable
• il faut redéfinir la méthode run()
2) une classe qui implémente l’interface Runnable
• il faut implémenter la méthode run()
9
Y. I. KHAMLICHI
CLASS THREAD
Les Constructeurs de
Thread
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 l'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.
11
INTERFACE RUNNABLE
EXÉCUTION D’UN
THREAD
Méthode start( ) :
« déroule » le code de la méthode « run » associée
Exécution en parallèle
Appel à run( ) directement : l’exécution serait alors
séquentielle (non parallèle) dans le même « thread »
Le thread est terminé lorsque la méthode « run » l’est
13
CYCLE DE VIE D’UN
THREAD
14
Les différents états d’un
thread
15
Lancer le thread
Un thread se lance grâce à la méthode start(). Une fois le
thread lancé, sa méthode run() s'exécute. Lorsque cette
méthode se termine, le thread meurt
Start est utilisé via le contrôleur de thread, i.e.:
[Link]();
[Link]();
16
Exécuter plusieurs
threads simultanément
Le principal intérêt des threads est qu’ils permettent de définir
plusieurs séquences d’instructions complétement indépendantes.
Dans certains cas, ces séquences peuvent même s’exécuter de façon
quasi simultanée,
Exemple :
Public class monThread extends Thread {
public void run() {
for (int i=1; i<1000; i++)
[Link](i);
}
public static void main(String[] args) {
new monThread().start();
new monThread().start();
}
}
17
Génération dynamique
du thread
new monThread().start();
new monThread().start();
18
Exemple
class Monthread extends Thread {
String Nom;
public Monthread (String Nom){[Link]=Nom;}
public void run(){
[Link](Nom);
}
}
public class Testhread {
public static void main(String[] args) {
Monthread A= new Monthread("Said");
Monthread B= new Monthread("Ali");
[Link]();
[Link]();
}
}
19
Les Méthodes
20
Start
start: exécute donc la méthode run associé au thread.
Quand un thread est lancé, vous ne pouvez pas le relancer
une 2e fois.
class SimpleThread extends Thread {
public void run() {
[Link]( « je démarre" );
}}
public class Restart {
public static void main( String args[] ) throws Exception {
SimpleThread T1= new SimpleThread();
[Link]();
[Link]( "en cours d’exécusion");
[Link](); [Link]
[Link]( "Fin"); at [Link](Unknown
Source)
}}
21
SLEEP
sleep: permet donc d'en dormir un thread un certain temps.
Pour utiliser sleep, il faudra capturer l'exception
InterruptedException.
via une implantation de la classe Runnable
[Link]((int)([Link]() * 1000));
sinon
sleep((int)([Link]() * 1000));
vu que la classe dérive directement de Thread.
22
YIELD
yield: met le thread courant dans l'état prêt pour permettre
à un autre thread de même priorité ou priorité supérieure
de s'exécuter.
class YieldThread extends Thread {
public void run() {
for ( int count = 0; count < 4; count++) {
[Link]( count + "de : " + getName() );
yield();
}}}
class TestYield {
public static void main( String[] args ) {
YieldThread first = new YieldThread();
YieldThread second = new YieldThread();
[Link](); [Link]();
[Link]( "Fin" );
}}
23
interrupt
interrompre un thread: 3 méthodes de la classe Thread
interviennent à ce niveau:
void interrupt(); pour interrompre un thread
boolean isInterrupted(); true s'il a été interrompu sinon false.
static boolean interrupted();true s'il a été interrompu sinon false
class NiceThread extends Thread {
public void run() {
while ( !isInterrupted() ) {[Link]( "From: " + getName() ); }
[Link]( "Clean up operations" );
}}
public class InterruptTest {
public static void main(String args[]) throws InterruptedException{
NiceThread T1= new NiceThread();
[Link]();
[Link]().sleep( 2 ); // attend le démarrage d’un autre thread
[Link]();}} //positionne un indicateur dans T1
24
Join
join: est utilisé pour mentionner au thread d'attendre la fin
d'un autre thread.
Coureur j = new Coureur ("Driss");
Coureur p = new Coureur ("Kamal");
// On lance les deux coureurs.
[Link]();
[Link]();
try { [Link](); [Link](); }
catch (InterruptedException e) {};
Coureur k = new Coureur ("Jamal");
[Link]() ;
Ici Jamal va se lancer après que Driss & Kamal terminent leur course.
25
Autres Méthodes
void destroy(); // détruit le Thread courant sans faire le
ménage.
String getName(); // retourne le nom du Thread.
int getPriority(); // retourne la priorité du Thread.
void setPriority(int newPriority); // changer la priorité du
Thread. (MAX_PRIORITY(10), MIN_PRIORITY(1), 5)
static boolean interrupted(); // teste si le Thread courant a
été interrompu.
void resume(); // redémarrer le Thread.
void stop(); // Arrêter le Thread
Void suspend(); // Arrêt momentané duThread
String toString(); // Renvoyer une représentation textuelle
du thread qui contient son nom, sa priorité, et le nom du
groupe auquel il appartient.
26
Exemple
class Coureur extends Thread {
String nom_coureur;
//constructeur de la classe
public Coureur (String str) { nom_coureur = str; }
public void run() {
for (int i =1; i<=10; i++) {
[Link](i*100 + " m par " + nom_coureur);
try {
sleep((int)([Link]() * 1000));
} catch (InterruptedException e) {}
}
[Link]( nom_coureur + " est arrive ! ");
}
}
27
Exemple
// classe pour tester la classe Coureur
class Course {
public static void main (String[] args) {
// Il s'agit d'une classe de coureurs
[Link]("Passage aux : ");
Coureur j = new Coureur ("Driss");
Coureur p = new Coureur ("Kamal ");
// On lance les deux coureurs.
[Link]();
[Link]();
}
}
28
Exemple
class Coureurapp implements Runnable {
String nom_coureur;
public Coureurapp (String str) {nom_coureur = str;}
public void run() {
for (int i =1; i<=10; i++) {
[Link](i*100 + " m par " + nom_coureur);
try {
[Link]((int)([Link]() * 1000));
} catch (InterruptedException e) {}
}
[Link]( nom_coureur + " est arrive ! ");
}
}
29
Exemple
// classe pour tester la classe Coureur
class Courseapp {
public static void main (String[] args) {
// Il s'agit d'une classe de coureurs
[Link]("Passage aux : ");
Coureurapp j = new Coureurapp ("Driss");
Thread tj = new Thread(j);
Coureurapp p = new Coureurapp ("Kamal");
Thread tp = new Thread(p);
// On lance les deux coureurs.
[Link]();
[Link]();
}
}
30
Autre Exemple
31
La synchronisation
Objectif : faire en sorte qu’un seul thread exécute une partie
du code
Blocage possible !!
Un thread n’est pas bloqué par lui-même
Ralentissement du code : attendre son tour
Synchroniser juste ce qui est nécessaire
32
La synchronisation
Nous avons mentionné que les Threads partagent les mêmes
ressources (mémoire, variables du processus etc.). Dans certaines
situations, il est nécessaire de synchroniser les threads pour
obtenir un résultat cohérent.
33
Problème de
Synchronisation
34
Problème de
Synchronisation
Soient deux threads T1 et T2 qui exécutent en parallèle .
La fonction ajoute(String) sur la même ListeTab. Leurs actions
peuvent être entrelacées, ainsi, plusieurs exécutions sont
possibles.
Par exemple :
(a1) (a2) (b1) (b2), est une exécution possible, cohérente ;
(b1) (b2) (a1) (a2), est une exécution possible, cohérente ;
(a1) (b1) (b2) (a2), est une exécution possible, mais incohérente : le
tableau ne contient pas la chaîne de caractères ajoutée par T1, et
la case de la liste est vide.
La fonction ajoute est appelée section critique. Plusieurs sections
critiques dépendantes ne doivent jamais exécuter leur code
simultanément (par plusieurs threads différents) : on dit qu'elles
sont en exclusion mutuelle
35
Synchronisation de bloc
Son effet est le suivant : pour exécuter le code, la méthode
doit verrouiller l'objet. Si celui-ci n'est pas déjà verrouillé,
tout va bien. Sinon, l'exécution du thread est suspendue
jusqu'à ce que l'objet soit libéré par l'autre thread qui
l'utilisait en le verrouillant. À ce moment, un des threads
qui veulent verrouiller l'objet obtient le verrou (clé) , et les
autres threads qui veulent un verrou restent suspendus.
36
Exemple 1.1
Exemple :
package monThread2;
public class Impression extends Thread{
int j = 1;
public Impression(String s) {super(s);}
Synchroniser l’objet
public void run(){
[Link]
synchronized ([Link]){
for (int i = 1; i <=10; i++){
[Link]("Impression de la page" + j + " du "+ getName());
j++; } } }
L’objet [Link] est
public static void main (String[] args){
verrouillé jusqu’à ce que
new Impression("premier document").start();
le traitement soit terminé
new Impression("deuxieme document").start();
} }
37
Exemple 1.1
Impression de la page1 du premier document
Résultat : Impression de la page2 du premier document
Impression de la page3 du premier document
Impression de la page4 du premier document
Impression de la page5 du premier document
Impression de la page6 du premier document
Impression de la page7 du premier document
Impression de la page8 du premier document
Impression de la page9 du premier document
Impression de la page10 du premier document
Impression de la page1 du deuxieme document
Impression de la page2 du deuxieme document
Impression de la page3 du deuxieme document
Impression de la page4 du deuxieme document
Impression de la page5 du deuxieme document
Impression de la page6 du deuxieme document
Impression de la page7 du deuxieme document
Impression de la page8 du deuxieme document
Impression de la page9 du deuxieme document
Impression de la page10 du deuxieme document
38
Exemple 1.2
Exemple sans synchronized :
package monThread2;
public class Impression extends Thread{
int j = 1;
public Impression(String s) {super(s);}
public void run(){
//synchronized ([Link]){
for (int i = 1; i <=10; i++){
[Link]("Impression de la page" + j + " du "+ getName());
j++; } } //}
public static void main (String[] args){
new Impression("premier document").start();
new Impression("deuxieme document").start();
} }
39
Exemple 1.2
Impression de la page1 du deuxieme document
Résultat : Impression de la page1 du premier document
Impression de la page2 du deuxieme document
Impression de la page2 du premier document
Impression de la page3 du deuxieme document
Impression de la page3 du premier document
Impression de la page4 du deuxieme document
Impression de la page4 du premier document
Impression de la page5 du deuxieme document
Impression de la page5 du premier document
Impression de la page6 du deuxieme document
Impression de la page6 du premier document
Impression de la page7 du deuxieme document
Impression de la page7 du premier document
Impression de la page8 du deuxieme document
Impression de la page8 du premier document
Impression de la page9 du deuxieme document
Impression de la page9 du premier document
Impression de la page10 du deuxieme document
Impression de la page10 du premier document
40
Exemple 2
Exemple :
public class Compte {
private double xSolde;
public Compte(double DépôtInitial) {
xSolde = DépôtInitial; }
public synchronized double solde() {
return xSolde; }
public synchronized void dépôt(double montant) {
xSolde = xSolde + montant; }
}
41
Exemple 2
42
Exemple 2
public class Banque {
public static void main(String [] arg) {
Compte monCompte = new Compte(2000.00);
Chèques c = new Chèques(monCompte);
Liquide l = new Liquide(monCompte);
new Thread(c).start();
new Thread(l).start();
}
}
43
Synchronisation de bloc
44
Synchronisation de bloc
45
ATTENDRE JUSQU’À…
Méthode wait (sur un objet)
[Link]( );
Appel dans une section synchronisée
Possibilité d’attendre que quelque chose réveille le thread
Le thread ne fait plus rien en attendant
Et il passe aussitôt la main
Réveil par la méthode notify
[Link]( );
Appel dans une section synchronisée
Ne débloque qu’un thread, on ne sait pas lequel
Réveil par notifyAll( );
Possibilité d’utiliser un délai max du wait( délai)
Dans ce cas, le thread doit gérer lui-même le fait de connaître la cause
de son déblocage (notify ou temps écoulé)
46