• Aucun résultat trouvé

Les tâches et la synchronisation en langage Java

N/A
N/A
Protected

Academic year: 2022

Partager "Les tâches et la synchronisation en langage Java"

Copied!
45
0
0

Texte intégral

(1)

Les tâches et la synchronisation en langage Java

Les threads, les verrous, les sémaphores et les moniteurs en Java

et les moniteurs en Java

D’après les cours de D. Genthial et B. Caylux

(2)

Généralités

E j tâ h t lé

z En java une tâche est un processus léger :

Î il partage l’espace mémoire de l’application qui l’a p g p pp q lancé.

Î il possède sa propre pile d’exécution.

Î il possède sa propre pile d exécution.

z En Java, un processus léger peut être créé par :

1. dérivation de la classe Thread.

2. implémentation de l’interface Runnable.

D t ti ffi i ll d S

z Documentation officielle de Sun :

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html

(3)

Th d Thread

z Un thread est constitué essentiellement d’une méthode run () ()

z Cette méthode est appelée par la méthode start()

start()

z Un Thread vit jusqu’à la fin de l’exécution de sa méthode run.

Î Un thread peut être endormi par sleep(nb de ms) p p p( )

Î Un thread peut passer son tour par yield()

Î Un thread peut se mettre en attente par wait()

Î Un thread peut se mettre en attente par wait()

(4)

Création de Thread par spécialisation p p de la classe Thread Défi iti d th d

class MonThread extends Thread{

Définition du thread

MonThread(. . .){

Constructeur }

public void run(){

. . . Algorithme décrivant

le comportement du thread le comportement du thread }

. . . }

}

Démarrage du thread

MonThread mt = new MonThread ();

mt.start() // exécute la méthode run de mt

(5)

Création de Thread par spécialisation de la classe Thread

E l

z Exemple

class MaPremiereTache extends Thread { public MaPremiereTache() {

public MaPremiereTache() { super();

} }

public void run() {

System.out.println(“Bonjour le monde !”);

} } ...

MaPremiereTache t = new MaPremiereTache ();

t.start(); // exécute la méthode run de t

(6)

Création de Thread par implémentation p p de l’interface Runnable

L’interface Runnable L interface Runnable

public abstract interface Runnable {

Runnable {

public abstract void run();

}

public class MaPremiereTache implements Runnable { ...

Utilisation

public void run() {

System.out.println(“Bonjour le monde !”);

}

}

(7)

Création de Thread par implémentation p p de l’interface Runnable

L’interface Runnable L interface Runnable

public abstract interface Runnable {

public abstract void run();

Cibl d Th d i

p }

Autre implémentation

class X extends . . . implements Runnable{

Thread leThread = new Thread(this);

Cible du Thread qui doit contenir la

définition de la

public void run(){

. . .

méthode run()

. . .

}

. . .

leThread.start(); // exécute la méthode run de la cible

leThread.start(); // exécute la méthode run de la cible

}

(8)

Création de Thread par implémentation

C é ti d’ tâ h à ti d’ bj t R bl

p p

de l’interface Runnable

z Création d’une tâche à partir d’un objet Runnable

Runnable maTache = new MaPremiereTache(...);

Thread leThread = new Thread(maTache);

leThread.start(); // démarrage

z ou simplement (tâche anonyme)

Runnable maTache = new MaPremiereTache(...);

new Thread(maTache).start();

z ou encore...

MaPremiereTache maTache = new MaPremiereTache(...);

new Thread(maTache).start();

(9)

Méth d t ti

Méthodes statiques

Ell i l h d l

z Elles agissent sur le thread appelant

Î Thread.sleep(long ms) p( g )

bloque le thread appelant pour la durée spécifiée;

spécifiée;

Î Thread.yield()

Le thread appelant relâche le processeur au Le thread appelant relâche le processeur au profit d’un thread de même priorité;

Th d tTh d()

Î Thread.currentThread()

retourne une référence sur le thread appelant;

(10)

Méth d d’i t

Méthodes d’instances

M Th d M Th d ()

MonThread p = new MonThread ();

z p.start() démarre le thread p;

z p.isAlive() détermine si p est vivant (ou terminé);

z p.join() p j () bloque l’appelant jusqu’à ce que p soit terminé; q pp j q q p ;

z p.setDaemon() attache l’attribut « daemon » à p;

z p setPriority(int pr) assigne la priorité pr à p;

z p.setPriority(int pr) assigne la priorité pr à p;

z p.getPriority() retourne la priorité de p;

(b d’ )

z …(beaucoup d’autres)

(11)

Cycle de vie d’un thread

Création: M t

Cycle de vie d un thread

Création

new … objet créé

Mort

start()

yield()

fin de la

fonction run En cours

d’exécution exécutable

yield()

d exécution

wait() notify() ou notifyAll()

délai du sleep()

join()

fy() fy ()

ou fin du thread bl é

dépassé

En attente bloqué

sleep()

(12)

A êt d’ tâ h Arrêt d’une tâche

z Un Thread dans l’état bloqué ou en attente peut être

z Un Thread dans l état bloqué ou en attente peut être arrêté par interrupt()

class MonThread extends Thread{

. . .

public void run(){

try{

try{

while (true){

. . .

sleep(100);

}

}catch(InterruptedException ie){

. . . }

MonThread t = new MonThread ();

t.start();

} }

. . . }

. . .

t.interrupt();

(13)

A êt d’ tâ h Arrêt d’une tâche

z L’itération peut être contrôlée par un booléen et

z L itération peut être contrôlée par un booléen et arrêtée par une fonction qui rend vrai le booléen.

class MonThread extends Thread{

boolean arret = false;

public void run(){

public void run(){

try{

while(!arret){

. . . }

}catch(InterruptedException ie){

. . . }

MonThread t = new MonThread ();

t.start();

} }

public void stop (){

arret = true;

} . . .

t.stop();

}

. . .

}

(14)

Arrêt d’une tâche

public void run() { public void run() {

try {

// Corps de la tâche ...

} catch (InterruptedException e) { // Terminer la tâche

...

return;

} fi ll { } finally {

// Code exécuté avant la fin de la tâche, quelle que soit // la cause qui l’a arrêtée (fin normale ou exception

// ou erreur) ...

}

}

}

(15)

J i t d th d Jointure de threads

z Un thread peut avoir à attendre la fin d’un ou

z Un thread peut avoir à attendre la fin d un ou plusieurs threads pour démarrer : join()

class MonThread extends Thread{

Thread precedent;

public MonThread( Thread p){

é éd t

précédent = p;

}

p blic oid run(){

public void run(){

try{

precedent.join(); // le thread reste bloqué tant que // precedent n’est pas terminé

// precedent n est pas terminé . . .

}catch(InterruptedException ie){

. . . }

} }

}

(16)

P i ité d th d Priorité des threads

z Les Threads ont une priorité qui va de

z Les Threads ont une priorité qui va de

Î Thread.MIN_PRIORITY (1)

Î Thread NORM PRIORITY (5)

Î Thread.NORM_PRIORITY (5)

Î Thread.MAX_PRIORITY (10)

z int getPriority() ;

z int getPriority() ;

z void setPriority(int p) ;

id D (b l ) d d

z void setDaemon(boolean on) permet de rendre un thread démon : thread qui s’exécute en tâche de f d

fond.

z Un programme Java se termine lorsque tous les threads user sont terminés (les threads daemon n’ont pas besoin d’être

sont terminés (les threads daemon n ont pas besoin d être

terminés).

(17)

Th d d l JVM Threads de la JVM

E l d th d d J

z En plus des threads du programme Java, une machine virtuelle Java exécute des threads dédiés à des tâches de gestion :

Î thread oisif (priorité 0): exécuté si aucun autre thread ne s’exécute;

Î ramasse-miettes (garbage collector, priorité 1): récupère les objets qui ne sont plus accessibles (référencés) Ce thread ne objets qui ne sont plus accessibles (référencés). Ce thread ne s’exécute que lorsqu’aucun autre thread (à part le thread oisif) ne s’exécute;

ti i d’h l è l é é i lié

Î gestionnaire d’horloge: gère tous les événements internes liés au temps;

Î thread de finalisation: appelle la méthode finalize( ) des objets

Î thread de finalisation: appelle la méthode finalize( ) des objets

récupérés par le ramasse-miettes.

(18)

Ordonnancement des tâches : la théorie

z Les threads exécutable se trouvent dans les queues de différentes

z Les threads exécutable se trouvent dans les queues de différentes priorités, gérées par le run-time de Java:

Î si plus d’un thread exécutable, Java choisit le thread de plus haute priorité;

priorité;

Î si plus d’un thread de plus haute priorité, Java choisit un thread arbitrairement;

Î un thread en cours d’exécution perd le CPU au profit d’un thread de

Î un thread en cours d’exécution perd le CPU au profit d un thread de plus haute priorité qui devient exécutable;

z par défaut, un thread a la même priorité que le thread qui l’a créé;

z la priorité peut être changée en appelant Thread.setPriority().

(19)

Ordonnancement des tâches : la réalité

L liti d’ ll ti d th d

z La politique d’allocation du processeur aux threads de même priorité n’est pas fixée par le langage.

Ell t êt é ti !!!

Î Elle peut être avec ou sans préemption!!!

z Pas de traitement cohérent de la priorité:

exemple: la priorité n’est pas utilisée par la méthode notify() pour choisir le processus à débloquer;

f

z La spécification du langage n’exige pas que les

priorités soient prises en compte par le runtime.

(20)

S h i ti

Synchronisation

z Comment empêcher plusieurs threads

z Comment empêcher plusieurs threads d’accéder en même temps à un objet ? Chaq e objet Ja a possède n erro

z Chaque objet Java possède un verrou d’exclusion mutuelle.

S h i ti d’ bl d’i t ti

Î Synchronisation d’un bloc d’instructions

synchronized (objet){

. . . // Aucun autre thread ne . . . // peut accéder à objet }

Î Synchronisation d’une méthode

Î Synchronisation d une méthode

synchronized void f(){

. . . // Aucun autre thread ne // t éd à l’ bj t . . . // peut accéder à l’objet

. . . // pour lequel est appelé la méthode f

}

(21)

Rappel : les verrous Rappel : les verrous

Type verrou = structure procédure init verrou (modifié v : verrou);

Type verrou structure ouvert : booléen;

attente : liste de tâches;

fin verrou;

procédure init_verrou (modifié v : verrou);

début

v.ouvert Å vrai;

v.attente Å vide;

; ;

fin init_verrou;

procédure verrouiller (modifié v : verrou);

début

procédure déverrouiller (modifié v : verrou);

début

si v.ouvert alors v.ouvert Å faux sinon

début

si v.attente ≠ vide alors

Sortir la première tâche de v.attente, sinon

Ajouter la tâche dans la liste v.attente dormir

finsi;

La réveiller sinon

v.ouvert Å vrai fi i

finsi;

fin verrouiller;

finsi;

fin déverrouiller;

(22)

Exemple : voie unique Exemple : voie unique

Tâche TrainGauche (modifié voie : verrou);

début

rouler;

rouler;

verrouiller(voie);

Passer;

dé ill ( i ) Tâche TrainDroit (modifié voie : verrou);

déverrouiller(voie);

rouler;

fin TrainGauche;

( );

début

rouler;

verrouiller(voie);

verrouiller(voie);

Passer;

déverrouiller(voie);

(23)

E l d bl h i d Exemple de bloc synchronized

Comment garantir une exécution atomique des commandes Comment garantir une exécution atomique des commandes suivantes ?

System.out.print (new Date ( )) ; System.out.print (" : ") ;

System.out.println (...) ;

(les méthodes print et println de la classe Printstream sont (les méthodes print et println de la classe Printstream sont

synchronisées )

Synchronized (System.out){

System.out.print (new Date ( ) ) ; System.out.print (" : ") ;

System.out.println (...) ; }

}

lorsqu’une méthode synchronized est appelée, le thread

appelant doit obtenir le verrou associé à l’objet pp j

(24)

S h i ti

Synchronisation

z La synchronisation par verrou peut

z La synchronisation par verrou peut

provoquer des « interblocages » (dead l k ) t l’ êt défi itif d

locks) amenant l’arrêt définitif de un ou plusieurs threads .

class MonThread1 extends Th d{

class MonThread2 extends Th d{

Thread{

public void run(){

synchronized(a){

Thread{

public void run(){

synchronized(b){

. . .

synchonized(b){

. . . }

. . .

synchonized(a){

. . . }

} } }

}

}

}

(25)

L J tili ti (1) Les verrous Java : utilisation (1)

z Synchronisation (verrouillage) sur un objet

public class Compte {

private double xSolde;

private double xSolde;

public Compte(double DépôtInitial) { xSolde = DépôtInitial;

}

public synchronized double solde() { return xSolde; etu So de;

}

public synchronized void dépôt(double montant) {

S ld S ld t t

xSolde = xSolde + montant;

} }

Î

Solde et Dépôt sont exécutées en exclusion mutuelle sur un

objet donné (xSolde)

(26)

L J tili ti (2) Les verrous Java : utilisation (2)

public class Chèques public class Liquide public class Chèques

implements Runnable { private Compte xCompte;

public class Liquide implements Runnable {

private Compte xCompte;

private Compte xCompte;

public Chèques(Compte c) { xCompte = c;

private Compte xCompte;

public Liquide(Compte c) { xCompte = c;

xCompte = c;

}

public void run() {

xCompte = c;

}

public void run() { public void run() {

double montant;

// Lecture du montant

public void run() { double montant;

// Lecture du montant . . .

xCompte.dépôt(montant);

} }

. . .

xCompte.dépôt(montant);

} }

} }

(27)

L J tili ti (3) Les verrous Java : utilisation (3)

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); q q ( p ) new Thread(c).start();

new Thread(l).start();

}

}

}

(28)

S h i ti

Synchronisation

Bl d’ tâ h

z Blocage d’une tâche

void wait();

Î sur un objet quelconque

Î sur un objet quelconque

z Réveil d’une tâche

z Réveil d une tâche

void notify();

Î sur l’objet cause du blocage

Î sur l objet cause du blocage

z Réveil de toutes les tâches é e de toutes es tâc es

void notifyAll();

Î sur l’objet cause du blocage

(29)

S h i ti

Synchronisation

La méthode wait() est définie dans la classe Object La méthode wait() est définie dans la classe Object.

z On ne peut utiliser cette méthode que dans un code synchronisé.

z Elle provoque l'attente du thread en cours d'exécution. Elle provoque l attente du thread en cours d exécution.

z Elle doit être invoquée sur l'instance verrouillée.

synchronized(unObjet){

try{

unObjet.wait(); // unObjet bloque l’exécution du thread }catch(InerruptedException ie){

}catch(InerruptedException ie){

}

P d t l th d tt d l Obj t t l hé

z Pendant que le thread attend, le verrou sur unObjet est relaché.

Î wait(long ms) attend au maximum ms millisecondes

Î ait(long ms int ns) attend a ma im m ms millisecondes

Î wait(long ms, int ns) attend au maximum ms millisecondes

+ ns nanosecondes

(30)

Synchronisation

L éth d tif () t d débl th d

z La méthode notify() permet de débloquer un thread.

synchronized(unObjet){

unObjet.notify(); // débloque un thread bloqué par unObjet

}

z La méthode notifyAll() permet de débloquer tous les threads.

synchronized(unObjet){

unObjet.notifyAll(); // débloque tous les threads // bloqués par unObjet

}

(31)

R l l it

Rappel : les moniteurs

M d l d iété ti liè

Module avec des propriétés particulières

z on n’a accès qu’aux primitives externes (publiques), pas aux variables (privées) ; (p ) ;

z les procédures sont exécutées en exclusion mutuelle et donc les variables internes sont manipulées en exclusion mutuelle.

z on peut bloquer et réveiller des tâches Le blocage et le réveil

z on peut bloquer et réveiller des tâches. Le blocage et le réveil

s’exprime au moyen de conditions.

(32)

R l l it

Rappel : les moniteurs

Conditions = variables, manipulables avec :

procédure attendre (modifié c : condition);

début

Bl l tâ h i l’ é t t l’ j t d l fil d’ tt t ié à Bloque la tâche qui l’exécute et l’ajoute dans la file d’attente associée à c Fin attendre;

fonction vide(c : condition) Æ un booléen;

début début

si la file d’attente associée à c est vide alors renvoyer(VRAI)

sinon

renvoyer(FAUX) renvoyer(FAUX) finsi

Fin vide;

procéduresignaler (modifié c : condition);

procédure signaler (modifié c : condition);

début

si non vide(c) alors

extraire la première tâche de la file associée à c la réveiller

finsi Fin signaler;

(33)

M it J (1) Moniteurs en Java (1)

z En java on dispose de moniteurs simplifiés

z En java on dispose de moniteurs simplifiés

z Définition d’une classe

bli l M it {

public class Moniteur {

private type uneVariable;

public synchronized unePrimitive( ) public synchronized unePrimitive(. . .)

throws InterruptedException { . . .

if ( )

if (. . .)

wait(); // le thread se met en attente sur la cible . . .

} }

public synchronized unePrimitive(. . .) { . . .

notify(); // réveil de la cible y . . .

}

(34)

M it J (2) Moniteurs en Java (2)

I lé t ti éd it d diti

z Implémentation réduite des conditions

public class Moniteur {

private type uneVariable;

private type uneVariable;

private Object uneCondition = new Object();

public unePrimitive(. . .) // pas synchronized throws InterruptedException {

. . .

if (. . .)

synchronized (uneCondition) {uneCondition.wait();}

. . . }

public synchronized unePrimitive(. . .) { . . .

synchronized (uneCondition)

{uneCondition.notify();}

(35)

R d it ( l) Rendez-vous avec un moniteur (rappel)

Moniteur RDV;

Point d’entrée Arriver Lexique

procédure Arriver();

début

i Å i + 1;

n : un entier constant = ??

i : un entier;

tous_là : une condition;

i Å i + 1;

si i < n alors

attendre(tous_là);

fi i

_

Début {Initialisations}

i

Å

0;

finsi

signaler(tous_là); {Réveil en cascade}

fin Arriver;

;

Fin RDV;

(36)

Rendez-vous en Java : moniteur simplifié

class RendezVous { class RendezVous {

private int nbattendus; // nombre attendus private int i; // nombre arrivés // constructeur

public RendezVous(int n) { nbattendus = n;

i = 0;

}

public synchronized void arriver() throws InterruptedException {

i++;

if (i b tt d ) { if (i < nbattendus) {

wait();

};

notify();

notify();

}

}

(37)

Rendez-vous en Java avec condition

class RendezVous { class RendezVous {

private int nbattendus; // nombre attendus private int i; // nombre arrivés

i j j // i i

private Object tousla = new Object(); // condition // constructeur

public RendezVous(int n) {

p ( ) {

nbattendus = n;

i = 0;

}

public void arriver() throws InterruptedException { i++;

if (i < nbattendus) {

synchronized(tousla) {tousla.wait();}

};

synchronized(tousla) {tousla notify();}

synchronized(tousla) {tousla.notify();}

}

}

(38)

L Sé h J

Les Sémaphores en Java

z Il est inutile de définir des sémaphores en

z Il est inutile de définir des sémaphores en Java, car les mécanismes fournis par le

l l h i ti t l

langage pour la synchronisation et le

partage de ressources sont suffisamment puissants pour résoudre tous les problèmes qu'on peut avoir à résoudre avec des

q p

sémaphores.

z Il est cependant intéressant de montrer

z Il est cependant intéressant de montrer avec quelle facilité ces mécanismes

ê ili é défi i d

peuvent être utilisés pour définir des

sémaphores .

(39)

R l Sé h

Rappel : Sémaphores

z Mécanisme de synchronisation entre processus

z Mécanisme de synchronisation entre processus.

z Un sémaphore S est une variable entière, manipulable par l’intermédiaire de deux opérations :

P (proberen) et V (verhogen) P (proberen) et V (verhogen) acquire release

acquire (S) S Å (S − 1) acqu e (S) S (S )

si S < 0, alors mettre le processus en attente ; sinon on poursuit l’exécution

release (S) S Å (S + 1) ; réveil d’un processus en attente.

Î

acquire (S) correspond à une tentative de franchissement. S’il n’y a pas de

j t l ti iti l tt d i d j t t t

jeton pour la section critique alors attendre, sinon prendre un jeton et entrer dans la section (S), puis rendre son jeton à la sortie de la section critique.

Î

Chaque dépôt de jeton release (S) autorise un passage. Il est possible de déposer des jetons à l’avance

déposer des jetons à l avance

(40)

é S

Réalisation de la classe Semaphore

public class Semaphore { public class Semaphore {

private int xVal; // la valeur du sémaphore

// En java, l'initialisation du sémaphore vient naturellement // dans le constructeur

Semaphore (int valeur_initiale) { xVal = valeur_initiale; }

// Aquire : noter l'indispensable synchronized peut // générer une InterruptedException (wait).

public synchronized void acquire() throws InterruptedException { xVal = xVal - 1;

while(xVal < 0) wait();

}

// Release

public synchronized void release() { xVal = xVal + 1;

if (xVal <= 0) notify();

}

}

(41)

G d th d Groupe de threads

z Un Thread peut faire partie d’un groupe de

z Un Thread peut faire partie d un groupe de Thread :

ThreadGroup tgl = new ThreadGroup(nom du groupe);

ThreadGroup tgl = new ThreadGroup(nom du groupe);

Thread t = new Thread(nom du goupe, nom du

thread);

(42)

A t éth d d l l Th d Autres méthodes de la classe Thread

z static int activeCount() nombre de threads actifs du même groupe ou d’un sous-groupe

du même groupe ou d un sous groupe.

z static void enumerate(Thread[ ] t) énumère dans le tableau t les threads actifs du même groupe

le tableau t les threads actifs du même groupe ou d’un sous-groupe.

t ti Th d tTh d() t

z static Thread currentThread() retoune une

référence au Thread courant.

(43)

Communication entre tâches

Partage de mémoire commune + exclusion mutuelle

Modèle général : producteur / consommateur Modèle général : producteur / consommateur

Producteur Æ Données Æ Consommateur

z La communication est en général asynchrone : une des deux tâches travaille en général plus vite que l’autre.

z Pour limiter les effets de l’asynchronisme, on insère un tampon

entre le producteur et le consommateur :

(44)

Producteur/Consommateur

avec tampon

(45)

Producteur/Consommateur avec tampon Producteur/Consommateur avec tampon

Moniteur Tampon; {Suppose Taille et Message connus}

Points d’entrée

déposer, retirer;

Lexique

nb : entier; {Nbre d’élt. dans le tampon (0..Taille)}

non_plein, non_vide : conditions; {Pour le blocage et le réveil}

tamp : tableau[0..Taille-1] de Messages;

tête, queue : entier; {O..Taille-1}

procédure déposer (consulté m:Message)

procédure retirer (consulté m:Message) début

si nb 0 alors

début

si nb = Taille alors

attendre(non_plein) finsi

{Ajouter m au tampon}

si nb = 0 alors

attendre(non_vide) finsi

{ Enlever m du tampon }

nb ‡nb + 1;

tamp[queue] ‡m;

queue ‡(queue+1) mod Taille;

signaler(non_vide);

fin déposer;

{ p }

m ‡ tamp[tête];

tête ‡ (tête+1) mod Taille;

nb ‡ nb - 1;

nb nb 1;

signaler(non_plein);

fin retirer;

Déb t Début

nb ‡ 0; tête ‡ 0; queue ‡ 0;

Fin Tampon;

Références

Documents relatifs

Grâce à cette nouvelle façon de stocker l’information, les transformations d’un objet par l’intermédiaire d’une méthode de sa classe sont visibles pour tous les objets de

La plate-forme et le langage Java sont issus d’un projet de Sun Microsystems datant de 1990. Généralement, on attribut sa paternité a trois de ses

Cliquez ici pour telecharger le

3.5 Conversions entre types tableaux ou

En matière yclage,les assauts de : volonté des industriels lisent pas pour l'instant à uer les filières illégales Irtation vers des pays lues ou africains, où ux équipements sont

– les applets Java (pour APPLication internET) sont des programmes lanc´es `a partir d’un fichier HTML (le langage de description de page d’Internet) par l’interm´ediaire d’un

public static boolean createTempFile(String p, String e, File dir) Création d'un chier temporaire (pas obli- gatoirement eacé à la n de l'appli- cation) dans le répertoire dir, dont

La VUE est l’interface. C’est une instance d’une classe graphique. Le CONTROLEUR est une instance d’une classe implémentant les Listeners nécessaires ; on appellera cette