You are on page 1of 135

Univerité hassan ii

de casablanca
Ecole supérieure de technologie

Programmation
orientée objet

Java Avancé

Préparé par :
Larbi Hassouni
Threads En Java

Préparé par : HASSOUNI Larbi

HASSOUNI Larbi 2
Définitions
• Un programme est multitâche quand il lance
(ou peut lancer) l’exécution de plusieurs
parties de son code en même temps
• A un moment donné, il comporte plusieurs
points d’exécution liés aux différentes
parties qui s'exécutent en parallèle

HASSOUNI Larbi 3
Systèmes d’exploitation
• Tous les systèmes d'exploitation modernes
sont multitâches et ils permettent l’exécution
de programmes multitâches
• Sur une machine monoprocesseur cette
exécution en parallèle est simulée
• Si le système est préemptif, il peut à tout
moment prendre la main à un programme
pour la donner à un autre
• Sinon, un programme garde la main jusqu’à ce
qu’il la cède à un autre
HASSOUNI Larbi 4
Threads et processus
• Le multitâche s'appuie sur les processus ou les
threads (processus légers)
• Chaque processus a son propre espace
mémoire (espace où sont rangées les valeurs
des variables utilisées par le processus)
• Un processus peut lancer plusieurs threads qui
se partagent le même espace mémoire et
peuvent donc se partager des variables
• Un thread prend moins de ressources système
qu’un processus
HASSOUNI Larbi 5
Exemples de thread
• L’interface graphique de l’utilisateur lance un
thread pour charger une image et continue à
traiter les événements générés par les actions
de l’utilisateur
• Le serveur réseau qui attend les demandes de
connexions venant des autres machines lance
un thread pour traiter chacune des demandes
• La multiplication de 2 matrices (m, p) et (p, n)
peut être effectuée en parallèle par m  n
threads
HASSOUNI Larbi 6
Utilité du multitâche
• Sur une machine multiprocesseurs il permet
d’améliorer les performances en répartissant les
différentes tâches sur différents processeurs
• Par exemple, le calcul du produit de 2 matrices
peut être réparti en un nombre de tâches
parallèles égal au nombre de processeurs,
• La répartition des tâches sur les processeurs est
le plus souvent faite automatiquement par le
système qui offre le multitâche
HASSOUNI Larbi 7
Utilité du multitâche (2)
• Sur une machine monoprocesseur, il peut aussi être
intéressant d’utiliser le multitâche pour
– modéliser plus simplement (simulation par
exemple)
– profiter des temps de pose d’une tâche (attente
d’entrées-sorties ou d’une action de l’utilisateur)
pour exécuter d’autres tâches
– réagir plus vite aux actions de l’utilisateur en
rejetant une tâche longue et non-interactive dans
un autre thread (par exemple, chargement d’une
image ou lecture de données qui proviennent
d’un réseau)
HASSOUNI Larbi 8
Programme comportant 3 threads
Système à multi processeurs Système à un seul processeurs

HASSOUNI Larbi 9
Comment opèrent les threads

Considérons un programme qui consiste en 3 activités:

1. Lecture d’un certain nombre de bloc de données à partir


d’un fichier

2. Effectuer des calculs sur chaque bloc de données

3. Ecrire les résultats des calculs dans un autre fichier

Vous pouvez organiser le programme de deux façons


différentes comme le montre le schéma suivant.

HASSOUNI Larbi 10
HASSOUNI Larbi 11
Problèmes du multitâche

• Il est souvent plus difficile d'écrire un


programme multitâche
• Et surtout, il est difficile de déboguer un
programme qui utilise le multitâche

HASSOUNI Larbi 12
Java et le multitâche

• Java supporte l'utilisation des threads


• A l’inverse de la plupart des autres langages,
le programmeur n'a pas à utiliser des librairies
natives du système pour écrire des
programmes multitâches.

HASSOUNI Larbi 13
Définiton desThreads en Java

• A tout thread Java sont associés


– un objet qui détermine le code qui est exécuté
par le thread. Cet objet est une instance d'une
classe qui implémente l'interface Runnable.
– un objet qui « contrôle » le thread et le
représente auprès des objets de l’application ;
on l’appellera le « contrôleur de thread ».
Cet objet est une instance de la classe Thread.

HASSOUNI Larbi 14
Interface Runnable

q La classe de l’objet qui définit le code à exécuter


doit implémenter l’interface Runnable

public interface Runnable {


void run();
} méthode qui contient
le code à exécuter par
le thread

HASSOUNI Larbi 15
Contrôleur de thread

• Le contrôleur d’un thread est un objet qui


– permet de contrôler l’exécution du thread (pour
le lancer en particulier)
– a des informations sur l’état du thread (son nom,
sa priorité, s’il est en vie ou non,…)
– est une instance de la classe Thread (ou une
classe fille)

HASSOUNI Larbi 16
Classe Thread

• Elle implémente l'interface Runnable (mais


la méthode run() ne fait rien)
• Une instance d’une classe fille de Thread
peut donc être à la fois un contrôleur de
thread et définir le code à exécuter

HASSOUNI Larbi 17
Classe Thread:
Constructeurs généralement utilisés
• Thread()
• Thread(String name)
• Thread(Runnable r)
• Thread(Runnable r,String name)

HASSOUNI Larbi 18
Thread()Allocates a new Thread object.

Thread(Runnable target)Allocates a new Thread object.

Thread(Runnable target, String name)Allocates a new Thread object.

Thread(String name)Allocates a new Thread object.

Thread(ThreadGroup group, Runnable target)Allocates a new Thread object.

Thread(ThreadGroup group, Runnable target, String name)Allocates a new Thread object so that
it has target as its run object, has the specified name as its name, and belongs to the thread group
referred to by group.

Thread(ThreadGroup group, Runnable target, String name, long stackSize)Allocates a


new Thread object so that it has target as its run object, has the specified name as its name, and
belongs to the thread group referred to by group, and has the specified stack size.

Thread(ThreadGroup group, String name)Allocates a new Thread object.

HASSOUNI Larbi 19
2 façons de créer
un contrôleur de thread

• 1ère façon : créer une instance d’une classe fille


de la classe Thread ;
la classe fille doit redéfinir la méthode run()
• 2ème façon : utiliser le constructeur
Thread(Runnable) de la classe Thread :
1. créer un Runnable (le code qui sera
contrôlé par le contrôleur)
2. le passer au constructeur de Thread

HASSOUNI Larbi 20
Créer un contrôleur de thread avec
une classe fille de la classe Thread
class ThreadTache extends Thread {
. . .
public void run() {
// Code qui sera exécuté par le thread
. . .
}
}

ThreadTache threadTache = new ThreadTache(…);

HASSOUNI Larbi 21
Créer un contrôleur de thread
avec l'interface Runnable
class Tache implements Runnable {
. . .
public void run() {
// Code qui sera exécuté par le thread
. . .
}
}

Tache tache = new Tache(…);


Thread t = new Thread(tache) ;

HASSOUNI Larbi 22
Quelle façon utiliser ?

• Si on veut hériter d’une autre classe pour la


classe qui contient la méthode run(), on
est obligé de choisir la 2ème façon
(Thread(Runnable))
• Il est aussi plus simple d’utiliser la 2ème
façon pour partager des données entre
plusieurs threads
• Sinon, l’écriture du code est (légèrement)
plus simple en utilisant la 1ère façon
HASSOUNI Larbi 23
Principales méthodes de la classe Thread
public void run(): Contient le code à exécuter par le thread.
public void start(): Démarre l'exécution du thread (Le met dans l'état
runnable : Eligible pour l'execution). La JVM lance l'exécution de la
méthode run().
public void sleep(long miliseconds): Met le thread qui est en cours
d'éxécution dans l'etat endormi pour la durée spécifiée en
milliseconds (cesse de s'executer temporairement).
public void join(): Le thread qui est en cours d'execution et qui
envoie un message à un autre thread th pour exécuter join()
(th.join())se met en attente jusqu'à ce que th meurt.
public void join(long miliseconds): Le thread qui est en cours
d'execution attend qu'un thread meurt pendant une durée spécifiée
en millisecondes.

HASSOUNI Larbi 24
public int getPriority(): retourne la priorité du thread.

public int setPriority(int priority): changes la priorité du thread.

public String getName(): retourne le nom du thread.

public void setName(String name): change le nom du thread.


public Thread currentThread(): retourne une réference vers le
thread qui est en cours d'exécution.

public int getId(): retourne l'id du thread.


public Thread.State getState(): returne l'état du thread.

HASSOUNI Larbi 25
public boolean isAlive(): teste si le thread est toujours en vie.
public void yield(): Met le thread en cours d'exécution en état de
pause temporaire pour permettre à d'autres thread de priorité
égale ou supérieure de s'exécuter.
public boolean isDaemon(): teste si le thread est un thread
demons.
public void setDaemon(boolean b): marque le thread comme un
thread demons (b=true) ou utilisateur (b=false). Par défaut un
nouveau thread est un thread utilisateur.
public void interrupt(): interrompe un thread, plus exactement,
positionne le flag d'interruption d'un thread à l'état "ON".
public boolean isInterrupted(): teste si le thread a été
interrompu. Autrement dit, teste si son flag d'interruption est
positionné à "ON".
public static boolean interrupted(): idem que isInterrupted(),
mais c'est une méthode statique.
HASSOUNI Larbi 26
Etats d'un thread
A thread can be in one of the following states:
• NEW : A thread that has not yet started is in this state
• RUNNABLE : A thread in the runnable state is executing in the Java virtual machine
but it may be waiting for other resources from the operating system such as
processor.
• BLOCKED: A thread in the blocked state is waiting for a monitor lock to enter a
synchronized block/method or reenter a synchronized block/method after calling
object.wait.
• WAITING : A thread is in the waiting state due to calling one of the following
methods:
– Object.wait with no timeout
– Thread.join with no timeout
A thread in the waiting state is waiting for another thread to perform a particular action.
For example, a thread that has called Object.wait() on an object is waiting for another
thread to call Object.notify() or Object.notifyAll() on that object. A thread that has
called Thread.join() is waiting for a specified thread to terminate
HASSOUNI Larbi 27
TIMED_WAITING : A thread is in the timed waiting
state due to calling one of the following methods
with a specified positive waiting time:
•Thread.sleep
•Object.wait with timeout
•Thread.join with timeout

HASSOUNI Larbi 28
Cycle de vie d'un thread Bloqué
(BLOCKED)
Ne perd pas
Bloqué le moniteur
(BLOCKED)
new Perd le Moniteur wait()
Thread() sleep()

notify()

Nouveau start() Eligible pour En


Thread l'exécution Exécution
(NEW) (RUNNABLE) (RUNNING)
yield()

return()ou fin d'exécution


Mort
(DEAD)

HASSOUNI Larbi 29
Nom d’un thread

• Le nom permet de faciliter le repérage des


threads durant la mise au point.
• Pour donner un nom à un thread, on peut
utiliser l'un des constructeurs suivant :
✓ Thread(String name)
✓ Thread(Runnable r, String name)
• Ou utiliser la méthode :
public void setName(String name)

HASSOUNI Larbi 30
Lancer l’exécution d'un thread
La méthode start() de la classe Thread est utilisée pour lancer
un thread nouvellement créé. Elle effectue les operations
suivantes:
❑ Un nouveau thread démarre (avec une nouvelle
"callstack").
❑ Le thread passe de l'état "New" à l'état "Runnable".
Lorsque le thread est sélectioné par le scheduler, sa méthode
run() se met en exécution en parallèle avec le code qui a
lance le thread.
Attention, une erreur serait d’appeler directement la méthode
run() : la méthode run() serait exécutée par le thread qui l’a
appelée et pas par un nouveau thread(Il n’ya pas création de
thread)
HASSOUNI Larbi 31
• Chaque thread lancé avec start possède sa propre
pile (call stack).
• Invoquer la méthode run() à partir du thread main(),
run() utilise la pile actuelle utilisée par le tread
main() plutôt que d'utiliser une nouvelle pile.

Invocation de run() à
Lancement des threads par start:
partir de main(): run() se
Chaque thread s'exécute avec une pile séparée
partage la même pile que
main()
HASSOUNI Larbi 32
Relancer un thread

Attention :
• On ne peut relancer un thread qui a déjà été lancé.
• Que l’exécution de la méthode run du thread soit
terminée ou non, si on relance un thread, on obtient
une java.lang.IllegalThreadStateException

HASSOUNI Larbi 33
Le "Scheduler" des threads en Java
• Le Scheduler des threads en java est la partie de la
JVM qui décide quel thread sera mis en exécution.
• Il n'y a pas de garantie sur le thread "runnable" qui
sera séléctioné par le Scheduler pour s'exécuter.
• Le Scheduler des threads utilise principalement deux
méthodes pour planifier l'exécution des threads :
– Planification "preemptive"
– "time slicing" ou quantum de temp.

HASSOUNI Larbi 34
Différence entre planification preemptive
et time slicing
• Sous la planification preemptive, le thread qui a la
plus haute priorité s'exécute jusqu'à ce qu'il se met
en état d'attente, ou se termine, ou un thread de
plus haute priorité rentre en existence.
• Sous "time slicing", un thread s'exécute pour une
partie du temps (quantum), puis rentre dans la
queue (ou pool) des treads runnable. Le scheduler
détermine par la suie quel thread se mettra en
exécution, en se basant sur la priorité et d'autres
facteurs.
HASSOUNI Larbi 35
Threads : Exemple 1
class Ecrit extends Thread{ public class TstThr1{
public static void main (String args[]){
public Ecrit (String texte, int nb, long attente){ Ecrit e1 = new Ecrit ("Salam\n", 10, 5) ;
this.texte = texte ; Ecrit e2 = new Ecrit ("Hello\n", 12, 10) ;
this.nb = nb ; Ecrit e3 = new Ecrit ("Bonjour\n", 5, 15) ;
this.attente = attente ; e1.start() ;
e2.start() ;
} e3.start() ;
public void run (){ System.out.println(« Je suis la fonction main »);
}
try{ }
for (int i=0 ; i<nb ; i++){
System.out.print (texte) ;
sleep (attente) ;
}
}
catch (InterruptedException e) {
} // impose par sleep
}
private String texte ;
private int nb ;
private long attente ;
} HASSOUNI Larbi 36
Threads : Exemple 2
class Ecrit implements Runnable{ public class TstThr2{
public static void main (String args[]){
public Ecrit (String texte, int nb, long attente){ Ecrit e1 = new Ecrit ("Salam\n", 10, 5) ;
this.texte = texte ; Ecrit e2 = new Ecrit ("Hello\n", 12, 10) ;
this.nb = nb ; Ecrit e3 = new Ecrit ("Bonjour\n", 5, 15) ;
this.attente = attente ;
Thread t1 = new Thread (e1) ; t1.start() ;
} Thread t2 = new Thread (e2) ; t2.start() ;
public void run (){ Thread t3 = new Thread (e3) ; t3.start() ;
try{ System.out.println(“Je suis la fonction main”);
}
for (int i=0 ; i<nb ; i++){ }
System.out.print (texte) ;
Thread.sleep (attente) ;
// attention Thread.sleep
}
}
catch (InterruptedException e) {
} // impose par sleep
}
private String texte ;
private int nb ;
private long attente ;
}
HASSOUNI Larbi 37
HASSOUNI Larbi 38
Threads : Exemple 3
class Ecrit implements Runnable{ public class TstThr3{
public Ecrit (String texte, int nb, long attente){ public static void main (String args[]){
Ecrit e1 = new Ecrit ("Salam\n", 10, 5) ;
this.texte = texte ; Ecrit e2 = new Ecrit ("Hello\n", 12, 10) ;
this.nb = nb ; Ecrit e3 = new Ecrit ("Bonjour\n", 5, 15) ;
this.attente = attente ; e1.start() ;
} e2.start() ;
public void start (){ e3.start() ;
Thread t = new Thread (this) ; System.out.println(« Je suis la fonction main »);
t.start() ; }
}
}
public void run (){
try{
for (int i=0 ; i<nb ; i++){
System.out.print (texte) ;
Thread.sleep (attente) ;
}
}
catch (InterruptedException e) {
} // impose par sleep
}
private String texte ;
private int nb ;
private long attente ;
} HASSOUNI Larbi 39
Threads : Exemple 4
class Ecrit implements Runnable{ public class MyTstThr4{
public Ecrit (String texte, int nb, long attente){ public static void main (String args[]){
this.texte = texte ; Ecrit e1 = new Ecrit ("Salam\n", 10, 5) ;
Ecrit e2 = new Ecrit ("Hello\n", 12, 10) ;
this.nb = nb ; Ecrit e3 = new Ecrit ("Bonjour\n", 5, 15) ;
this.attente = attente ;
} Thread t1 = new Thread (e1) ; t1.start() ;
public void run (){ Thread t2 = new Thread (e2) ; t2.start() ;
try{ Thread t3 = new Thread (e3) ; t3.start() ;
for (int i=0 ; i<nb ; i++){
System.out.print (texte) ; try{
for(int i=0; i<5; i++){
Thread.sleep (attente) ; System.out.println("Fonction main");
// attention Thread.sleep Thread.sleep(100);
} }
} }
catch (InterruptedException e) { catch(InterruptedException e){
} // impose par sleep }
}
System.out.println("Je suis la fonction main");
private String texte ;
private int nb ; }
private long attente ; }
}

HASSOUNI Larbi 40
Types de Threads
• On distingue deux types de threads
– les threads utilisateur
– les démons
• La différence :
– la JVM fonctionne tant qu’il reste des threads
utilisateurs en exécution
– la JVM s’arrête s’il ne reste plus que des démons

HASSOUNI Larbi 41
Thread démons
(Daemon Thread)
• Un thread "Daemon" en java est un thread
fournisseur de service qui fournit des services au
thread utilisateur. Son cycle de vie dépend du cycle
de vie des threads utilisateurs.
• Lorsque tous les threads utilisateurs meurent, La JVM
termine automatiquement les threads démons.
• Il y a beucoup de threads démons qui s'exécutent
automatiquement (gc : garbage collector, finalize :
finalizer, …etc). (Pour voir tous les details, utilizer
l'utilitaire "jconsole")
HASSOUNI Larbi 42
Points à retenir sur les threads démons

• Un thread démons fournit un service à un thread


utilisateur pour supporter des tâches d'arrière plan.
• Il n'a aucun role sinon servir les threads utilisateurs.
C'est pour cette raison que la JVM termine
automatiquement un thread démons lorsque tous
les threads utilisateurs se terminent.
• Son cycle de vie depend des threads utilisateurs.
• Il a une faible priorité.

HASSOUNI Larbi 43
Threads démons
• La méthode:
void setDaemon(boolean true)
de la classe Thread permet d’indiquer que le
thread sera un démon (thread utilisateur par
défaut)
• Elle doit être appelée avant le démarrage du
thread par l’appel de start()

HASSOUNI Larbi 44
HASSOUNI Larbi 45
Threads demons et arret brutal
class Ecrit extends Thread import java.util.Scanner;
{ public Ecrit (String texte, long attente) public class Demons
{ this.texte = texte ; { public static void main (String args[])
this.attente = attente ; { Ecrit e1 = new Ecrit ("Salam\n", 5) ;
} Ecrit e2 = new Ecrit ("Hello\n", 10) ;
Ecrit e3 = new Ecrit ("Bonjour\n", 35) ;
public void run ()
e1.setDaemon (true) ; e1.start() ;
{ try e2.setDaemon (true) ; e2.start() ;
{ while (true) // boucle infinie e3.setDaemon (true) ; e3.start() ;
{ if (interrupted()) return ; int n = new Scanner(System.in).nextInt() ;
System.out.print (texte) ; // met fin au main, donc ici aux trois autres threads démons
sleep (attente) ; }
} }
}
catch (InterruptedException e)
{ return ; // on peut omettre return ici Exécuter le en mode
} console
}

private String texte ;


private long attente ;
}

HASSOUNI Larbi 46
Threads : Exemple 5 (1/2)
import java.io.IOException;
public class TryThread extends Thread {
public TryThread(String firstName, String secondName, long delay) {
this.firstName = firstName; // Store the first name
this.secondName = secondName; // Store the second name
this.aWhile = delay; // Store the delay
setDaemon(true); } // Thread is daemon
public static void main(String[] args) {
// Create three threads
Thread first = new TryThread(« Said ", « AOUITA ", 200L);
Thread second = new TryThread(« Younes ", « ELAYNAOUI ", 300L);
Thread third = new TryThread(« Nawal ", « MOUTAWAKIL ", 500L);
System.out.println("Press Enter when you have had enough...\n");
first.start(); second.start(); third.start(); // Start the third thread
try {
System.in.read(); // Wait until Enter key pressed
System.out.println("Enter pressed...\n");
} catch (IOException e) { // Handle IO exception
System.err.println(e); // Output the exception }
System.out.println("Ending main()");
return;
}
HASSOUNI Larbi 47
Threads : Exemple 5 (2/2)

// Method where thread execution will start


@Override
public void run() {
try {
while(true) { // Loop indefinitely...
System.out.print(firstName); // Output first name
sleep(aWhile); // Wait aWhile msec.
System.out.print(secondName + "\n"); // Output second name
}
} catch(InterruptedException e) { // Handle thread interruption
System.out.println(firstName + secondName + e); // Output the exception
}
}

private String firstName; // Store for first name


private String secondName; // Store for second name
private long aWhile; // Delay in milliseconds
}

HASSOUNI Larbi 48
Threads : Exemple 6 (1/2)
import java.io.IOException;
public class JumbleNames implements Runnable {
// Constructor
public JumbleNames(String firstName, String secondName, long delay) {
this.firstName = firstName; // Store the first name
this.secondName = secondName; // Store the second name
aWhile = delay; // Store the delay
}
// Method where thread execution will start
public void run() {
try {
while(true) {
System.out.print(firstName);
Thread.sleep(aWhile);
System.out.print(secondName+"\n");
}
} catch(InterruptedException e) {
System.out.println(firstName + secondName + e);
} }

HASSOUNI Larbi 49
Threads : Exemple 6 (2/2)
public static void main(String[] args) {
// Create three threads
Thread first = new Thread(new JumbleNames("Hopalong ", "Cassidy ", 200L));
Thread second = new Thread(new JumbleNames("Marilyn ", "Monroe ", 300L));
Thread third = new Thread(new JumbleNames("Slim ", "Pickens ", 500L));
// Set threads as daemon
first.setDaemon(true); second.setDaemon(true); third.setDaemon(true);
System.out.println("Press Enter when you have had enough...\n");
first.start(); // Start the first thread
second.start(); // Start the second thread
third.start(); // Start the third thread
try {
System.in.read(); // Wait until Enter key pressed
System.out.println("Enter pressed...\n");
} catch (IOException e) { // Handle IO exception
System.err.println(e); // Output the exception
}
System.out.println("Ending main()"); return;
}
private String firstName; private String secondName; private long aWhile;}
HASSOUNI Larbi 50
Dormir
• La méthode static de la classe Thread
public static void sleep(long millis)
throws InterruptedException
fait dormir le thread qui l'appelle un certain nombre
de millisecondes
• Si elle est exécutée dans du code synchronisé, le
thread ne perd pas le moniteur (au contraire de wait())
• La syntaxe est :
public static void sleep(int millis) throws InterruptedException

Exception
•InterruptedException -- Si le thread en cours est interrompu par un autre
thread, l’exception InterruptedException est lancée et son flag d’interruption est
initialisé.

HASSOUNI Larbi 51
Attente de la fin d’un thread
• Si dans un thread vous voulez attendre jusquà ce qu’un
autre thread meurt, vous pouvez appeler la méthode
join() pour le thread à attendre.
• La syntaxe est:
➢ threadAattendre.join(); : Le thread en cours attend
jusqu’à ce que threadAAttendre meurt;
➢ threadAattendre.join(long millis);
➢ threadAattendre.join(long millis, int nanos);
• La méthode join() peut lancer l’exception
InterruptedException si le thread en cours est interrompu
par un autre thread, par consequent vous devez mettre
dans un bloc try block et capter (catch) l’exception.
HASSOUNI Larbi 52
class FaitQuelqueChose implements Runnable {
// attribut propre au thread
protected String msg;

// constructeur
public FaitQuelqueChose(String msg) {
this.msg = msg;
}
// méthode d’exécution de la thread
public void run(){
System.out.println("run: (" + msg + ") début !");
try {
Thread.sleep(5000);
}
catch (Exception e) {}
System.out.println("run: (" + msg + ") milieu...");
try {
Thread.sleep(5000);
}
catch (Exception e) {}
System.out.println("run: (" + msg + ") fin !");
}
}
HASSOUNI Larbi 53
public class ThreadEx {
public static void main(String[] args) throws Exception {
System.out.println("main: demarre un");
Thread t1 = new Thread(new FaitQuelqueChose("un"));
t1.start();
try {
Thread.sleep(2500);
}
catch (Exception e) {}
System.out.println("main: demarre deux");

Thread t2 = new Thread(new FaitQuelqueChose("deux"));


t2.start();
System.out.println("main: attente fin execution...");
t1.join();
System.out.println("main: t1 est fini");
t2.join();
System.out.println("main: t2 est fini");
}
}
HASSOUNI Larbi 54
main: demarre un
run: (un) début !
main: demarre deux
main: attente fin execution...
run: (deux) début !
run: (un) milieu...
run: (deux) milieu...
run: (un) fin !
main: t1 est fini
run: (deux) fin !
main: t2 est fini

HASSOUNI Larbi 55
Exécution de ThreadEx
C:\>java MineThreadEx

main: demarre un main


run: (un) debut ! un
main: demarre deux
deux
main: attente fin
execution...
run: (deux) debut !
run: (un) milieu...
run: (deux) milieu...
run: (un) fin !
main: t1 est fini
run: (deux) fin !
main: t2 est fini
HASSOUNI Larbi 56
Passer la main

• La méthode static de la classe Thread


public static void yield()
permet de passer la main à un autre thread
de priorité égale ou supérieure
• Lorsqu’un thread exécute yield, il prend le
temps de voir s’il y a d’autres threads de
priorité égale ou supérieure qui sont en
attente. Si c’est le cas, la main est passée,
sinon le thread reprend son exécution
HASSOUNI Larbi 57
public class YieldingThread extends Thread {
private int countDown = 5;
private static int threadCount = 0;
public YieldingThread() {
super("" + ++threadCount);
start();
}
public String toString() {
return "#" + getName() + ": " + countDown;
}
public void run() {
while (true) {
System.out.println(this);
if (--countDown == 0)
return;
Yieldinyield();
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++)
new YieldingThread();
}
}
HASSOUNI Larbi 58
Interruption d'un thread

• Si un thread se trouve dans l'état endormie ou


d'attente(i.e. sleep() or wait() est invoquée),
l'appel de la méthode interrupt() sur le thread
met fin à l'etat endormi ou d'attente en
lançant l'exception InterruptedException.
• Si le thread ne se trouve dans un état endormi
ou d'attente, appeller la méthode interrupt()
n'interrompe pas le thread met place le flag
interrup du thread à l'état true.
HASSOUNI Larbi 59
Interruption de threads
class Ecrit extends Thread{ public class TstInter {
public Ecrit (String texte, long attente){ public static void main (String args[]) {
this.texte = texte ; Ecrit e1 = new Ecrit ("bonjour ", 5) ;
this.attente = attente ; Ecrit e2 = new Ecrit ("bonsoir ", 10) ;
} Ecrit e3 = new Ecrit ("\n", 35) ;
e1.start() ;
public void run (){
e2.start() ;
try{ e3.start() ;
while (true) { // boucle infinie System.out.println(«main : avant interruption e1 »);
if (interrupted()) return ; e1.interrupt() ; // interruption premier thread
System.out.print (texte) ; System.out.println ("\n** Arret premier thread **") ;
sleep (attente) ; System.out.println(«main : avant interruption e2 »);
} e2.interrupt() ; // interruption deuxième thread
e3.interrupt() ; // interruption troisième thread
}
System.out.println ("\n* Arret deux derniers threads *") ;
catch (InterruptedException e){ }
return ; // on peut omettre return ici }
}
}

private String texte ;


private long attente ;
}

HASSOUNI Larbi 60
Exécution de TstIntr

main : avant interruption e1

bonsoir bonjour
** Arret premier thread **
main : avant interruption e2

* Arret deux derniers threads *

HASSOUNI Larbi 61
Partage de données
entre plusieurs threads
• Le plus simple est de créer les threads
en utilisant une classe qui implémente
Runnable et de mettre les données
partagées comme variables static
de cette classe.

HASSOUNI Larbi 62
Synchronisation entre threads

HASSOUNI Larbi 63
Dans ce qui suit, nous allons discuter les capacités
basiques du langage Java pour gérer la synchronisation
entre les threads.
La librairie de concurrence fournie par les packages:
• java.util. concurrent,
• java.util.concurrent.atomic,
• java.util.concurrent.locks
Contient des classes qui implémente des facilités de
gestion des threads spécialisées,

HASSOUNI Larbi 64
Section critique
• L’utilisation de threads peut entraîner des
besoins de synchronisation pour éviter les
problèmes liés aux accès simultanés aux
variables
• En programmation, on appelle section critique
une partie du code qui ne peut être exécutée
en même temps par plusieurs threads sans
risquer de provoquer des anomalies de
fonctionnement
HASSOUNI Larbi 65
Exemple de problème
• Si x = 2, le code x = x + 1;
exécuté par 2 threads, peut donner en fin
d’exécution 3 ou 4 suivant l’ordre d’exécution :
1. T1 : lit la valeur de x (2)
2. T2 : lit la valeur de x (2)
3. T1 : calcul de x + 1 (3)
4. T2 : calcul de x + 1 (3)
5. T1 : range la valeur calculée dans x (3)
6. T2 : range la valeur calculée dans x (3)
• x contient 3 au lieu de 4 !

HASSOUNI Larbi 66
Synchronisation
• Il faut donc éviter l’exécution simultanée de
sections de code critiques par plusieurs threads

• Si plusieurs threads veulent exécuter en même


temps une section critique, on devra les
synchroniser pour qu’ils exécutent cette section
les uns après les autres

• En java les sections critiques sont représentées


par du code synchronisé sur un objet

HASSOUNI Larbi 67
Méthodes synchronized
class MyClass {
synchronized public void method1() {
// Code for the method...
}
synchronized public void method2() {
// Code for the method...
}
public void method3() {
// Code for the method...
}
}

HASSOUNI Larbi 68
HASSOUNI Larbi 69
Synchronisation de threads
class Nombres {
public void calcul() {
n++ ;
carre = n*n ;
}
public void affiche () {
System.out.println (n + " a pour carre " + carre) ;
}
private int n=0, carre ;
}

class ThreadCalcul extends Thread{ class ThreadAffiche extends Thread {


public ThreadCalcul (Nombres nomb){ public ThreadAff iche(Nombres nomb) {
this.nomb = nomb ; this.nomb = nomb ;
} }
public void run (){ public void run () {
try { try {
while (!interrupted()){ while (!interrupted()) {
nomb.calcul () ; nomb.affiche() ;
sleep (50) ; sleep (75) ;
} }
} }
catch (InterruptedException e) {} catch (InterruptedException e) {}
} }
private Nombres nomb ; private Nombres nomb ;
} HASSOUNI Larbi } 70
Synchronisation de threads
Import java.util.Scanner;
public class Synchronisation1 {
public static void main (String args[]) {
Nombres nomb = new Nombres() ;
Thread calc = new ThrCalc (nomb) ;
Thread aff = new ThrAff (nomb) ;
System.out.println ("Suite de carres - tapez retour pour arreter") ;
calc.start() ; >java NonSynchr1
aff.start() ; Suite de carres - tapez retour pour arreter
String s = new Scanner(System.in).nextLine(); 1 a pour carre 1
calc.interrupt() ; 2 a pour carre 4
aff.interrupt() ; 3 a pour carre 9
} 5 a pour carre 25
} 6 a pour carre 49
8 a pour carre 64
9 a pour carre 100
11 a pour carre 121
13 a pour carre 169
14 a pour carre 196
16 a pour carre 256
17 a pour carre 289
18 a pour carre 324
HASSOUNI Larbi 71
Synchronisation de threads
class Nombres{
public /* synchronized */ void calcul(){
n++ ;
try { Thread.sleep (100) ;}
catch (InterruptedException e) {}
carre = n*n ;
}
public /* synchronized */ void affiche (){
System.out.println (n + " a pour carre " + carre) ;}
private int n=0, carre ;
}
class ThreadCalcul extends Thread{ class ThreadAffiche extends Thread {
public ThreadCalcul (Nombres nomb){ public ThreadAffiche (Nombres nomb) {
this.nomb = nomb ; this.nomb = nomb ;
} }
public void run (){ public void run () {
try { try {
while (!interrupted()){ while (!interrupted()) {
nomb.calcul () ; nomb.affiche() ;
sleep (50) ; sleep (75) ;
} }
} }
catch (InterruptedException e) {} catch (InterruptedException e) {}
} }
private Nombres nomb ; private Nombres nomb ;
} HASSOUNI Larbi } 72
Synchronisation de threads
>java Synchr1a
import java.util.Scanner; Suite de carres - tapez retour pour arreter
public class Synchronisation2 { 1 a pour carre 0
public static void main (String args[]) { 1 a pour carre 0
Scanner stdin = new Scanner(System.in); 2 a pour carre 1
2 a pour carre 1
Nombres nomb = new Nombres() ; 3 a pour carre 4
Thread calcul = new ThreadCalcul (nomb) ; 3 a pour carre 4
Thread affiche = new ThreadAffiche (nomb) ; 4 a pour carre 9
4 a pour carre 9
System.out.println ("Suite de carres – 5 a pour carre 16
tapez retour pour arreter") ; 5 a pour carre 16
calcul.start() ; 6 a pour carre 25
affiche.start() ; 6 a pour carre 25
7 a pour carre 36
String s = stdin.nextLine(); 7 a pour carre 36
calcul.interrupt() ; 8 a pour carre 49
affiche.interrupt() ; 8 a pour carre 49
9 a pour carre 64
} 9 a pour carre 64
} 10 a pour carre 81
10 a pour carre 81
11 a pour carre 100
11 a pour carre 100
12 a pour carre 121
12 a pour carre 121
HASSOUNI Larbi 73
Synchronisation de threads
class Nombres {
public synchronized void calcul() {
n++ ;
carre = n*n ;
}
public synchronized void affiche () {
System.out.println (n + " a pour carre " + carre) ;
}
private int n=0, carre ;
}

class ThrCalc extends Thread{ class ThrAff extends Thread {


public ThrCalc (Nombres nomb){ public ThrAff (Nombres nomb) {
this.nomb = nomb ; this.nomb = nomb ;
} }
public void run (){ public void run () {
try { try {
while (!interrupted()){ while (!interrupted()) {
nomb.calcul () ; nomb.affiche() ;
sleep (50) ; sleep (75) ;
} }
} }
catch (InterruptedException e) {} catch (InterruptedException e) {}
} }
private Nombres nomb ; private Nombres nomb ;
} HASSOUNI Larbi } 74
Synchronisation de threads
import java.util.Scanner;
public class Synchr1 {
public static void main (String args[]) {
Scanner stdin = new Scanner(System.in); C:\>java Synchr1
Nombres nomb = new Nombres() ; Suite de carres - tapez retour pour arreter
1 a pour carre 1
Thread calc = new ThrCalc (nomb) ; 2 a pour carre 4
Thread aff = new ThrAff (nomb) ; 4 a pour carre 16
5 a pour carre 25
System.out.println ("Suite de carres – 6 a pour carre 36
tapez retour pour arreter") ; 8 a pour carre 64
9 a pour carre 81
calc.start() ; 11 a pour carre 121
aff.start() ; 12 a pour carre 144
14 a pour carre 196
String s = stdin.nextLine(); 15 a pour carre 225
calc.interrupt() ; 17 a pour carre 289
18 a pour carre 324
aff.interrupt() ; 20 a pour carre 400
} 21 a pour carre 441
23 a pour carre 529
} 24 a pour carre 576
26 a pour carre 676
27 a pour carre 729

HASSOUNI Larbi 75
Moniteur ou verrou d’un objet

• En Java, l’implémentation du code


synchronisé repose sur les moniteurs
(verrous) des objets
• Chaque objet Java possède un moniteur
• Un seul thread peut posséder le moniteur
d’un objet à un moment donné
• Si un autre thread veut acquérir le même
moniteur, il est mis en attente

HASSOUNI Larbi 76
Synchronisation avec les moniteurs

• Un thread t acquiert le moniteur d’un objet


en exécutant du code synchronisé sur cet
objet
• t rend le moniteur en quittant le code
synchronisé (ou en appelant la méthode
wait() de l’objet o)
• Il peut quitter le code synchronisé
normalement, ou si une exception est lancée
et non saisie
HASSOUNI Larbi 77
Synchronisation
• Aucun autre thread ne peut exécuter du code
synchronisé sur le même objet o tant que t exécute
le code synchronisé
• Si un autre thread veut exécuter du code synchronisé
sur o, il est mis en attente
• Lorsque t quitte le code synchronisé ou se met en
attente par o.wait(), un des threads en attente
peut redémarrer
• Les autres threads en attente auront la main à tour
de rôle (si tout se passe bien…)

HASSOUNI Larbi 78
Exemple
public class Compte {
private double solde;

public void deposer(double somme) {


solde = solde + somme;
}

public double getSolde() {


return solde;
}
}

HASSOUNI Larbi 79
Exemple (suite)
• On lance 3 threads du type suivant :
Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 100; i++) {
compte.deposer(1000);
}
}
};
• A la fin de l’exécution, on n’obtient pas nécessairement
300.000
• Il faut rendre deposer (et getSolde) synchronisée :
public synchronized
void deposer(double somme)
HASSOUNI Larbi 80
Synchronisation et performances
• L’exécution de code synchronisé nuit aux
performances
• Surtout s’il provoque des blocages entre
threads ; si pas de blocage, peu de perte de
performance
• Mais, de plus, du code synchronisé peut
empêcher des optimisations (inlining) au
moment de la compilation

HASSOUNI Larbi 81
Méthodes statiques

• Si on synchronise une méthode static,


on bloque le moniteur de la classe
• On bloque ainsi tous les appels à des
méthodes synchronisées de la classe (mais
pas les appels synchronisés sur une
instance de la classe)

HASSOUNI Larbi 82
Méthode synchronisée et héritage

• La redéfinition d’une méthode


synchronisée dans une classe fille peut ne
pas être synchronisée
• De même, la redéfinition d’une méthode
non synchronisée peut être synchronisée

HASSOUNI Larbi 83
wait et notify

HASSOUNI Larbi 84
Exécution conditionnelle
• Lorsqu’un programme est multi-tâche, la
situation suivante peut se rencontrer :
– Un thread t1 ne peut continuer son exécution
que si une condition est remplie
– Le fait que la condition soit remplie ou non
dépend d’un autre thread t2
• Par exemple, t1 veut utiliser le résultat d’un
calcul effectué par t2

HASSOUNI Larbi 85
Exécution conditionnelle (2)
• Une solution coûteuse serait que t1 teste la
condition à intervalles réguliers
• Les méthodes wait() et notify() de la
classe Object permettent de programmer
plus efficacement ce genre de situation

HASSOUNI Larbi 86
Schéma d’utilisation de wait-notify
• Cette utilisation demande un travail coopératif
entre les threads t1 et t2 :
1. Ils se mettent d’accord sur un objet commun
objet
2. Arrivé à l’endroit où il ne peut continuer que si la
condition est remplie, t1 se met en attente :
objet.wait();
3. Quand t2 a effectué le travail pour que la condition
soit remplie, il le notifie :
objet.notify();
ce qui débloque t1

HASSOUNI Larbi 87
Exemple d’utilisation de wait et notifyAll

HASSOUNI Larbi 88
class ThreadAjout extends Thread{

public ThreadAjout (Reserve r, int vol, int delai){


this.vol = vol ; this.r = r ; this.delai = delai ;}

public void run (){


try{
while (!interrupted()){
r.ajoute (vol) ;
sleep (delai) ;}}
catch (InterruptedException e) {}
}

private int vol ;


private Reserve r ;
private int delai ;
}

HASSOUNI Larbi 89
class ThreadPuise extends Thread{

public ThreadPuise (Reserve r, int vol, int delai){


this.vol = vol ; this.r = r ; this.delai = delai ;
}

public void run (){


try{
while (!interrupted()){
r.puise (vol) ;
sleep (delai) ; }
}
catch (InterruptedException e) {}
}

private int vol ;


private Reserve r ;
private int delai ;
}

HASSOUNI Larbi 90
import java.util.Scanner;
public class Synchro3{
public static void main (String args[]){
Reserve r = new Reserve () ;
ThreadAjout ta1 = new ThreadAjout (r, 100, 15) ;
ThreadAjout ta2 = new ThreadAjout (r, 50, 20) ;
ThreadPuise tp = new ThreadPuise (r, 300, 10) ;
System.out.println ("Suivi de stock --- Taper entree pour arreter ") ;
ta1.start () ; ta2.start () ; tp.start () ;
String s = new Scanner(System.in).nextLine();
ta1.interrupt () ; ta2.interrupt () ; tp.interrupt () ;
}
}
HASSOUNI Larbi 91
Besoin de synchronisation
• Le mécanisme d’attente-notification lié à un
objet met en jeu l’état interne de l’objet ;
pour éviter des accès concurrent à cet état
interne, une synchronisation est nécessaire
• Les appels:
-objet.wait()
-objet.notify()
-objet.notifyAll())
ne peuvent donc être effectués que dans du
code synchronisé sur objet
HASSOUNI Larbi 92
Méthode wait()
• public final void wait()
throws InterruptedException
• objet.wait()
– nécessite que le thread en cours possède le
moniteur de objet
– bloque le thread qui l’appelle, jusqu’à ce qu’un
autre thread appelle la méthode
objet.notify() ou objet.notifyAll()
– libère le moniteur de l’objet (l’opération « blocage
du thread – libération du moniteur » est atomique)

HASSOUNI Larbi 93
Méthode notifyAll()

• public final void notifyAll()


• objet.notifyAll()
– nécessite que le thread en cours possède le
moniteur de objet
– débloque tous les threads qui s’étaient bloqués sur
l’objet avec objet.wait()

HASSOUNI Larbi 94
Méthode notifyAll()
• Un seul des threads débloqués va récupérer le
moniteur ; on ne peut prévoir lequel
• Les autres devront attendre qu’il relâche le
moniteur pour être débloqués à tour de rôle,
mais ils ne sont plus bloqués par un wait
• En fait, souvent ils se bloqueront à nouveau
eux-mêmes (s’ils sont dans une boucle while
avec wait)

HASSOUNI Larbi 95
Méthode notify()
• objet.notify()
– idem notifyAll() mais
– ne débloque qu’un seul thread
• On ne peut prévoir quel sera le thread
débloqué et, le plus souvent, il vaut donc mieux
utiliser notifyAll()

HASSOUNI Larbi 96
Déblocage des threads

• Le thread débloqué (et élu) ne pourra


reprendre son exécution que lorsque le thread
qui l’a notifié rendra le moniteur de l’objet en
quittant sa portion de code synchronisé
• Le redémarrage et l’acquisition se fait dans une
opération atomique

HASSOUNI Larbi 97
notify perdus

• Si un notifyAll() (ou notify()) est


exécuté alors qu'aucun thread n'est en attente,
il est perdu : il ne débloquera pas les wait()
exécutés ensuite

HASSOUNI Larbi 98
Exemple avec wait-notify
• Les instances d’une classe Depot contiennent
des jetons
• Ces jetons sont
– déposés par un producteur
– consommés par des consommateurs
• Les producteurs et consommateurs sont des
threads

HASSOUNI Larbi 99
Exemple avec wait-notify
public class Depot {
private int nbJetons = 0;
public synchronized void donneJeton() {
try {
while (nbJetons == 0) {
wait();
}
nbJetons--;
}
catch (InterruptedException e) {}
}

HASSOUNI Larbi 100


Exemple avec wait-notify
public synchronized void recois(int n) {
nbJetons += n;
notifyAll();
}

HASSOUNI Larbi 101


Variante de wait

• Si on ne veut pas attendre éternellement


une notification, on peut utiliser une des
variantes suivantes de wait :
public void wait(long timeout)
public void wait(long timeout,
int nanos)
• 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é)

HASSOUNI Larbi 102


Moniteurs réentrants

• Un thread qui a acquis le moniteur d’un


objet peut exécuter les autres méthodes
synchronisées de cet objet ; il n’est pas
bloqué en demandant à nouveau le
moniteur

HASSOUNI Larbi 103


Affectations atomiques
• Il est inutile de synchroniser une partie de
code qui ne fait qu'affecter (ou lire) une valeur
à une variable de type primitif de longueur 32
bits ou moins (int, short, …)
• En effet, la spécification du langage Java
spécifie qu'une telle affectation ne peut être
interrompue pour donner la main à un autre
thread
• Mais, cette spécification n'assure rien pour les
affectations de double et de long !
HASSOUNI Larbi 104
Groupes de threads en Java
• Java fournit un moyen commode pour regrouper plusieurs threads dans
un seul objet. Ceci permet d'effectuer une même operation sur tous les
threads du même groupe, par un simple appel de méthode.
• Un groupe de threads peut avoir des groupes de threads enfants.
• Un groupe de thread est implémenté par la classe java.lang.ThreadGroup.
public class ThreadGroup extends Object implements
Thread.UncaughtExceptionHandler
• Constructeurs de la classe ThreadGroup
• La classe ThreadGroup possède uniquement deux constructeurs.
Constructeur Description

ThreadGroup(String name) Crée un groupe de threads avec le


nom spécifié.

ThreadGroup(ThreadGroup parent, Crée un groupe de threads, en


String name) spécifiant son groupe de threads
parent, et son nom.
HASSOUNI Larbi 105
Importantes méthodes de la classe ThreadGroup
• Il ya plusieurs méthodes dans la classe ThreadGroup. La liste ci-dessous
fournit les noms des plus importantes.
Méthode Description
Returns an estimate of the number of active
int activeCount() threads in this thread group and its
subgroups.
void destroy() Destroys this thread group and all of its
subgroups.
String getName() returns the name of this group.
ThreadGroup getParent() returns the parent of this group.
void interrupt() interrupts all threads of this group.
void list() prints information of this group to standard
console.
Called by the Java Virtual Machine when a
Void thread in this thread group stops because of
uncaughtException(Thread t, an uncaught exception, and the thread does
Throwable e) not have a specific
Thread.UncaughtExceptionHandler installed.

HASSOUNI Larbi 106


Exemple de code pour regrouper plusieurs threads.
ThreadGroup tg1 = new ThreadGroup("Group A");
Thread t1 = new Thread(tg1,new MyRunnable(),"one");
Thread t2 = new Thread(tg1,new MyRunnable(),"two");
Thread t3 = new Thread(tg1,new MyRunnable(),"three");
Les trois threads appartiennent au même groupe tg1 de nom
"Group A".
➢ tg1 représente l'objet groupe de threads,
➢ MyRunnable est une classe qui implémente l'interface
Runnable
➢ "one", "two" and "three" sont les noms des threads.
Maintenant, il est possible d'interrompre les trois threads par
une seule ligne de code.
Thread.currentThread().getThreadGroup().interrupt();
HASSOUNI Larbi 107
Exemple de programme utilisant ThreadGroup
public class ThreadGroupDemo implements Runnable{
@Override
public void run(){
while(!Thread.currentThread().interrupted()){
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String[] args){
ThreadGroupDemo runnable = new ThreadGroupDemo();
ThreadGroup tg1 = new ThreadGroup("Parent ThreadGroup");
Thread t1 = new Thread(tg1, runnable, "one");
t1.start();
Thread t2 = new Thread(tg1, runnable, "two");
t2.start();
Thread t3 = new Thread(tg1, runnable, "three");
t3.start();
System.out.println("Thread Group name : " + tg1.getName());
tg1.list();
tg1.interrupt();
}
}
HASSOUNI Larbi 108
Shutdown Hook
• The shutdown hook can be used to perform cleanup resource
or save the state when JVM shuts down normally or abruptly.
Performing clean resource means closing log file, sending
some alerts or something else. So if you want to execute some
code before JVM shuts down, use shutdown hook.
• When does the JVM shut down?
The JVM shuts down when:
✓ user presses ctrl+c on the command prompt
✓ System.exit(int) method is invoked
✓ user logoff
✓ user shutdown etc.

HASSOUNI Larbi 109


The addShutdownHook(Runnable r) method

The addShutdownHook() method of Runtime class is used to register the thread with the
Virtual Machine.
Syntax: public void addShutdownHook(Runnable r){}
The object of Runtime class can be obtained by calling the static factory method
getRuntime(). For example:
Runtime r = Runtime.getRuntime();

Factory method
The method that returns the instance of a class is known as
factory method.

HASSOUNI Larbi 110


Simple example of Shutdown Hook
class MyThread extends Thread{
public void run(){
System.out.println("shut down hook task completed..");
}
}
public class TestShutdown1{
public static void main(String[] args)throws Exception {
Runtime r=Runtime.getRuntime();
r.addShutdownHook(new MyThread());
System.out.println("Now main sleeping... press ctrl+c to exit");
try{Thread.sleep(3000);}catch (Exception e) {}
} }
Note: The shutdown sequence can be stopped by invoking the halt(int)
method of Runtime class.
HASSOUNI Larbi 111
Same example of Shutdown Hook by annonymous class:

public class TestShutdown2{


public static void main(String[] args)throws Exception {
Runtime r=Runtime.getRuntime();
r.addShutdownHook(new Runnable(){
public void run(){
System.out.println("shut down hook task completed..");
}
}
);
System.out.println("Now main sleeping... press ctrl+c to exit");
try{Thread.sleep(3000);}catch (Exception e) {}
}
}
HASSOUNI Larbi 112
Priorités

HASSOUNI Larbi 113


Principe de base
• Si plusieurs threads de même priorité sont en
exécution, on ne peut pas prévoir quel thread va
prendre la main
• S’ils sont en attente d’exécution, un thread de
plus grande priorité prendra toujours la main
avant un autre thread de priorité plus basse
• Cependant, il peut arriver exceptionnellement
qu’un thread continue son exécution alors que
des threads de priorité supérieure sont en attente
d’exécution

HASSOUNI Larbi 114


Niveaux de priorité
• Un nouveau thread a la même priorité que le
thread qui l’a créé
• En général, tous les threads ont la même priorité
(NORM_PRIORITY =5)
• Il faut faire appel à la méthode setPriority si
on veut modifier cette priorité par défaut
• Le paramètre de setPriority doit être
compris entre MIN_PRIORITY(1) et
MAX_PRIORITY(10)

HASSOUNI Larbi 115


Threads et exceptions
Threads et exceptions

• Si une exception n’est pas traitée (par un


bloc try-catch), elle interrompt
l’exécution du thread courant mais pas des
autres threads

• La méthode run ne peut déclarer lancer


une exception contrôlée car elle redéfinit
une méthode sans clause « throws »

HASSOUNI Larbi 117


Depuis Java 5, Il existe l'interface
UncaughtExceptionHandler qui contient une seule
méthode, uncaughtException(Thread t, Throwable e),
et qui permet de récupérer les exceptions non gérées
avant que le thread ne meure définitivement.

Vous pouvez alors définir votre propre gestionnaire


d'exceptions non gérées et informer vos threads que
celui-ci existe grâce à la méthode
setDefaultUncaughtExceptionHandler().
HASSOUNI Larbi 118
Nested Classes
Modifier and Class and Description
Type
static class Thread.State A thread state.
static interface Thread.UncaughtExceptionHandler Interface for
handlers invoked when a Thread abruptly
terminates due to an uncaught exception.
@FunctionalInterface
public static interface Thread.UncaughtExceptionHandler{
void uncaughtException(Thread t, Throwable e);
}

Method invoked when the given thread terminates due to the


given uncaught exception.
HASSOUNI Larbi 119
setUncaughtExceptionHandler
public void setUncaughtExceptionHandler(Thread.
UncaughtExceptionHandler eh)
Set the handler invoked when this thread abruptly terminates due to
an uncaught exception.
A thread can take full control of how it responds to uncaught
exceptions by having its uncaught exception handler explicitly set. If
no such handler is set then the thread's ThreadGroup object acts as
its handler.
Parameters:
eh : the object to use as this thread's uncaught exception handler.
If null then this thread has no explicit handler.

HASSOUNI Larbi 120


getUncaughtExceptionHandler
public Thread.UncaughtExceptionHandler getUnca
ughtExceptionHandler()
Returns the handler invoked when this thread abruptly
terminates due to an uncaught exception. If this thread has
not had an uncaught exception handler explicitly set then
this thread's ThreadGroup object is returned, unless this
thread has terminated, in which case null is returned.
Returns:
the uncaught exception handler for this thread

HASSOUNI Larbi 121


setDefaultUncaughtExceptionHandler
public
static void setDefaultUncaughtExceptionHandler(Thread.U
ncaughtExceptionHandler eh)
Set the default handler invoked when a thread abruptly terminates due to an
uncaught exception, and no other handler has been defined for that thread.
Uncaught exception handling is controlled first by the thread, then by the
thread's ThreadGroup object and finally by the default uncaught exception handler.
If the thread does not have an explicit uncaught exception handler set, and the
thread's thread group (including parent thread groups) does not specialize its
uncaughtException method, then the default handler's uncaughtException method
will be invoked.
Parameters:
eh - the object to use as the default uncaught exception handler. If null then there is
no default handler.

HASSOUNI Larbi 122


getDefaultUncaughtExceptionHandler
public
static Thread.UncaughtExceptionHandler getD
efaultUncaughtExceptionHandler()
Returns the default handler invoked when a thread abruptly
terminates due to an uncaught exception. If the returned
value is null, there is no default.
Returns:
the default uncaught exception handler for all threads

HASSOUNI Larbi 123


import java.lang.Thread.UncaughtExceptionHandler;

public class MyUncaughtExceptionHandler implements


UncaughtExceptionHandler{

public void uncaughtException(Thread t, Throwable e) {


System.out.println(t.getName() + ": Une exception de type
: " +e.getClass().getName());
}
}

HASSOUNI Larbi 124


import java.lang.Thread.UncaughtExceptionHandler;

public class MyUncaughtExceptionHandler2 implements


UncaughtExceptionHandler{

public void uncaughtException(Thread t, Throwable e) {


System.out.println("!!!!!!!! " + t.getName() + ":
!!!!!!!!Une exception de type : " +e.getClass().getName() );
}
}

HASSOUNI Larbi 125


import java.util.Random;
public class ThreadException extends Thread{
public ThreadException(String name){
setName(name);
setDefaultUncaughtExceptionHandler(new
MyUncaughtExceptionHandler());
}
public void run(){
Random rand = new Random();
while(true){
int cas = rand.nextInt(5);

switch(cas){
case 0 : int i = 10 / 0; break;
case 1 : Object str = "toto"; double d = (double) str;
break;
default :
System.out.println(getName() + ": aucune erreur...");
break;
} } }}

HASSOUNI Larbi 126


public class Main {
public static void main(String[] args){

for(int i = 0; i < 6; i++){


Thread t = new ThreadException("Thread-" + i);
if (i%2 == 0){
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler2());
}
t.start();
}
}
}

HASSOUNI Larbi 127


Utilisation de EXECUTORS

Bien à vous

HASSOUNI Larbi 128


HASSOUNI Larbi 130
Pool de thread : Exemple de programme
import java.util.concurrent.*;

public class ExecutorDemo {


public static void main(String[] args) {
// Create a fixed thread pool with maximum three threads
ExecutorService executor = Executors.newFixedThreadPool(3);

// Submit runnable tasks to the executor


executor.execute(new PrintChar('a', 100));
executor.execute(new PrintChar('b', 100));
executor.execute(new PrintNum(100));

// Shut down the executor


executor.shutdown();
}
}

HASSOUNI Larbi 131


// The task for printing a specified character in specified times
class PrintChar implements Runnable {
private char charToPrint; // The character to print
private int times; // The times to repeat

/** Construct a task with specified character and number of


* times to print the character
*/
public PrintChar(char c, int t) {
charToPrint = c;
times = t;
}

/** Override the run() method to tell the system


* what the task to perform
*/
public void run() {
for (int i = 0; i < times; i++) {
System.out.print(charToPrint);
}
}
}

HASSOUNI Larbi 132


// The task class for printing number from 1 to n for a given n
class PrintNum implements Runnable {
private int lastNum;

/** Construct a task for printing 1, 2, ... i */


public PrintNum(int n) {
lastNum = n;
}

/** Tell the thread how to run */


public void run() {
for (int i = 1; i <= lastNum; i++) {
System.out.print(" " + i);
}
}
}

HASSOUNI Larbi 133


HASSOUNI Larbi 134
HASSOUNI Larbi 135

You might also like