Vous êtes sur la page 1sur 32

Institut National des Télécommunication et des Technologies

d'Information et de la Communication INT-TIC d'Oran Algérie

Programmation Multitâches
(Multithreading)
COURS : PROGRAMMATION RÉSEAU

R. HACHEMI
Programmation Multitâches (Multithreading)

Les machines actuelles, mono et multi processeurs, ont la capacité


d’exécuter plusieurs processus simultanément.

Machines monoprocesseur : à un instant donné, les ressources de la


machine sont utilisées par un seul processus.

Ouvrir plusieurs applications (un logiciel de traitement de texte, un


navigateur web,…) en même temps.
Programmation Multitâches (Multithreading)

Octroie d’intervalles de temps très courts aux différents processus.

Ce partage de ressources par les processus donne l’impression de la


simultanéité.

Threads : une même application peut être conçue de sorte que


plusieurs tâches (threads) peuvent être exécutées simultanément.
Threads en Java

Java reprend ce mécanisme pour produire des programmes multi-


tâches.
Un programme est constitué de plusieurs unités d’exécution,
appelées « threads ».

Le programmeur n’a pas à se soucier du partage des ressources


entre les tâches d’une application (géré par la machine virtuelle Java
(JVM)).

Rôle programmeur : coordonner les actions de certains threads pour


préserver la cohérence des données (ne pas exécuter une même
portion de code « critique » en même temps).
Threads en Java

Chaque thread correspond à une pile d’exécution.

Il existe deux façons de créer des threads en Java:

 En exploitant la classe java.lang.Thread,

 En créant une classe spécifique implémentant


l’interface java.lang.Runnable.
La Classe java.lang.Thread

Création d’un thread : instance d’une classe héritant de la classe


java.lang.Thread.

Thread possède deux principaux constructeurs :

public Thread() ;
public Thread (Runnable runnable) ;
//Car Thread implémente l’interface Runnable

Attribuer un nom à un Thread :

public Thread(String threadName) ;


La Classe java.lang.Thread

Le code à exécuter par le thread doit impérativement être placé


dans la méthode run().

public class MaClasseThread extends Thread {


public void run() {
// Code à exécuter
}
}
La Classe java.lang.Thread

Pour lancer un thread (après l’avoir instancié), il faut appeler sa


méthode start().

MaClasseThread monThread = new MaClasseThread();


MonThread.start();
La Classe java.lang.Thread
Exemple
class MonThread extends Thread {
int iterations = 10;
public MonThread(String nom) {
super(nom);
}
public MonThread(String nom, int iterations) {
super(nom);
this.iterations = iterations ;
}
public void run() {
for (int i=0; i<this.iterations; i++)
System.out.println(this.getName() +
"(iteration " + (i+1) + " )" );
}
}
La Classe java.lang.Thread
Exemple
public class TestMonThread {
public static void main(String[] args) {
MonThread thread1 = new MonThread("A");
MonThread thread2 = new MonThread("B", 15);
System.out.println("Avant l'appel de start l'etat de " +
thread1.getName() + " est : " +
thread1.getState());
System.out.println("Avant l'appel de start l'etat de " +
thread2.getName() + " est : " +
thread2.getState());
thread1.start();
thread2.start();
while( thread1.isAlive() || thread2.isAlive())
System.out.println(
Thread.currentThread().getName() +
"faire quelque chose !");
}
}
La Classe java.lang.Thread
Méthodes
Méthode Rôle

void setName(String) Définit le nom du thread.

String getName() Retourne le nom du thread.

int getPriority () Retourne la priorité du thread.

void setPriority (int) Modifie la priorité.

Thread.State getState () Renvoie l’état du thread.

void start () Lancement du thread et appel de la méthode run().

void run () Méthode contenant le code à exécuter par le thread.

void suspend () Suspend le thread (méthode obsolète !).

void resume () Reprend l’activité du thread, suspendu par préalablement


par suspend() (méthode obsolète !).
La Classe java.lang.Thread
Méthodes
void destroy () Arrête brutal du thread.

void join () Attend la fin du thread.

void yield () Indique à la JVM que le thread peut être suspendu pour
donner la main à d’autres threads.

boolean isAlive() Renvoie true si le thread est actif.

boolean isInterrupted() Renvoie true si le thread a été interrompu.

ThreadGroup getThreadGroup() Renvoie le groupe de threads (un objet ThreadGroup)


auquel appartient le thread.

static void sleep(long) Met le thread en attente pendant le temps (en


millisecondes) spécifié en paramètre.

static int enumerate (Thread[]) Copie dans un tableau de threads, les threads actifs.
Cycle de vie d’un Thread
état du thread lors de son
instanciation
Cycle de vie d’un Thread

Après appel de start().


Alternance entre activation et interruption par le
système.
Ces deux états ne sont pas distinguables par
getState().
Appel de yield()  peut être interrompu.
Le thread est mis en pause : par appel de la
Cycle de vie d’un Thread
méthode sleep().
Un thread en pause ne peut pas être lancé
par le système.
Le thread repasse dans l’état RUNNABLE
lorsque le temps est écoulé.
Cycle de vie d’un Thread

Le thread peut être mis dans une liste


d’attente associée à un objet suite à un appel
à la méthode wait() de l’objet.
Il repassera à l’état RUNNABLE en appelant
les méthode notify() ou notifyAll().
Cycle de vie d’un Thread

Le thread est bloqué pour ressource non


disponible (ressource de type entrée/sortie :
un fichier, un socket, …).
Le thread retourne à l’état RUNNABLE
lorsque la ressource est disponible.
Cycle de vie d’un Thread

Terminaison de l’exécution (thread « mort


») : fin de la méthode run().
On ne peut plus le relancer à nouveau par
la méthode start().
Cycle de vie d’un Thread

• isAlive() : tester si un thread est en vie : elle renvoie false si le


thread est dans l’un des deux états NEW et TERMINATED et true
dans tous les autres cas.

• Certaines opérations sont interdites dans certains états : impossible


de relancer un thread dans un état TERMINATED avec start().
Une telle tentative lèvera une exception de type
IllegalThreadStateException.
Cycle de vie d’un Thread
Exemple
public class TestMonThread {
public static void main(String[] args) {
// instanciation et lancement des deux threads
// ...
while( thread1.isAlive() || thread2.isAlive()) {
System.out.println(
Thread.currentThread().getName() +
"faire quelque chose !");
System.out.println(
Thread.currentThread().getName() +
" : Etat de " + thread1.getName() +
" est " + thread1.getState());
System.out.println(
Thread.currentThread().getName() +
" : Etat de " + thread2.getName() +
" est " + thread2.getState());
}
}
}
Interface java.lang.Runnable

Inconvénient de l’utilisation directe de la classe Thread :


impossibilité d’hériter d’une autre classe (ex : une Frame qui est en
même temps un thread).

Utilisation de l’interface Runnable :

interface Runnable {
public void run() ;
}
Interface java.lang.Runnable

Création d’un thread, il suffit de lier un objet de la classe Thread à


un objet de notre classe, en utilisant l’un des deux constructeurs :

public Thread (Runnable runnable) ;


public Thread (Runnable runnable, String name) ;
Interface java.lang.Runnable
Exemple
class MaClasse implements Runnable {
long duree = 5000;
String nom;
public MaClasse (String nom) {
super(nom);
this.nom = nom;
}
public MaClasse (String nom, long duree) {
super(nom);
this.nom = nom;
this.duree = duree ;
}
public String getName() { return nom; }
public void run() {
long debut = System.currentTimeMillis();
while( System.currentTimeMillis() < debut+this.duree ) {
System.out.println("Message de " + this.getName());
try{
Thread.sleep(500);
} catch (InterruptedException ex) {}
}
}
}
Interface java.lang.Runnable
Exemple
public class TestMonThread {
public static void main(String[] args) {
Thread thread1 = new Thread (new MaClasse ("A"));
Thread thread2 = new Thread (new MaClasse("B", 8000));
System.out.println("Avant l'appel de start l'etat de " +
thread1.getName() + " est : " + thread1.getState());
System.out.println("Avant l'appel de start l'etat de " +
thread2.getName() + " est : " + thread2.getState());
thread1.start();
thread2.start();
while ( thread1.isAlive() || thread2.isAlive()) {
try {
System.out.println(Thread.currentThread().getName()
+ " : Etat de " + thread1.getName() + " est "
+ thread1.getState());
System.out.println(Thread.currentThread().getName()
+ " : Etat de " + thread2.getName() + " est "
+ thread2.getState());
Thread.sleep(800);
} catch (InterruptedException ex) {}
}
}
}
Synchronisation des Threads

Lorsque deux ou plusieurs threads partagent certaines données de


l’application, il peut être nécessaire de synchroniser ces threads afin
de conserver l’intégrité des données.
 Méthode avec le mot clé synchronized : cette méthode ne
peut être utilisée par un thread si elle est déjà utilisée par un autre
thread (même si ce dernier n’est pas en cours d’exécution).
Les threads cherchant à utiliser une méthode synchronisée sont mis
dans une liste d’attente jusqu’à ce que le thread utilisant la méthode
termine son travail.
Synchronisation des Threads
Exemple

class CompteBancaire {
private int solde = 2000;
public int getSolde () {
return this.solde;
}
public void retrait (int somme) {
if (somme < this.solde) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
this.solde -= somme;
System.out.println("Compte débité de " + somme + " dinars");
}
}
}
Synchronisation des Threads
Exemple
class RunCompteBancaire implements Runnable {
private CompteBancaire cb;
public RunCompteBancaire (CompteBancaire cb) {
super();
this.cb = cb;
}
public void run () {
cb.retrait(2000) ;
System.out.println("Il vous reste " + cb.getSolde() + " dinars");
}
}

public class TestCompteBancaire {


public static void main(String[] args) {
CompteBancaire cb = new CompteBancaire();
Thread thread1 = new Thread (new RunCompteBancaire (cb));
Thread thread2 = new Thread (new RunCompteBancaire (cb));
thread1.start();
thread2.start();
}
}
Synchronisation des Threads
Exemple
Puisqu’on effectue un retrait d’une somme de 2000 dinars, le
deuxième thread exécutant la méthode retrait(int) ne devrait
pas pouvoir effectuer ce retrait en raison de la non satisfaction de la
condition (if somme <= solde). Or, on peut très bien avoir
l’exécution suivante :

Compte débité de 2000 dinars


Il vous reste 0 dinars
Compte débité de 2000 dinars
Il vous reste -2000 dinars
Synchronisation des Threads
Exemple
Ce scénario d’exécution se produit comme suit :
• Le 1er thread exécute la méthode retrait(int) et commence par
vérifier la condition.
• L’environnement donne ensuite la main au 2ème thread. Celui-ci exécute la
même instruction.
• Les deux threads vont pouvoir par la suite effectuer le retrait.
Même scénario lorsqu’un objet est utilisé par plusieurs threads en
même temps.

Ces threads peuvent être en mesure d’exécuter, de manière


concurrente, une méthode qui modifie l’état de l’objet.
Synchronisation des Threads
Exemple
Empêcher les autres threads d’utiliser la méthode tant que le thread
qui est entrain de l’utiliser n’a pas l’a pas fini de manière complète,
même lorsqu’il n’est pas en cours d’exécution.
Marquer la méthode avec le mot clé synchronized.

Public synchronized void retrait (int somme) {


if (somme < this.solde) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
this.solde -= somme;
System.out.println("Compte débité de " + somme + " dinars");
}
}
Synchronisation d’un Bloc

Pour permettre de réduire la longueur des sections de codes


critiques, Java permet de marquer synchronized seulement un
bloc de code. (un thread détenant le verrou de l’objet pourra
débloquer le verrou plus vite).

synchronized void methode1 () {


// bloc de code critique
...
}
...
void methode2 () {
...
synchronized (this) {
// bloc de code critique
...
}
}
Synchronisation d’un Bloc

Méthodes de classes (statiques) :

void methodeInstance () {
...
synchronized (this) {
// bloc de code critique
...
}
}
...
void methodeClasse () {
...
synchronized (MaClasse.class) {
// bloc de code critique
...
}
}

Vous aimerez peut-être aussi