java et le multitâche - freedaniel.tschirhart.free.fr/java/cours/javaetlemultitache.pdf · daniel...
TRANSCRIPT
Java et le multitâcheJava et le multitâche
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
2
Le multitâche dans Java 2Le multitâche dans Java 2� La gestion du multitâche dans java 2 était particulière
indigente.� Gestion minimale des tâches.� Gestion des accès concurrents très limitées.� Pas de mécanisme producteur - consommateur.� Pas de mécanisme lecteur - rédacteur.� Pas de mutex, sémaphores, événements, rendez-vous.
� Il a fallut attendre 10 ans pour que Sun Microsystemsremédie à ces manquements avec Java 5.
� La présentation suivante s’applique à Java 5
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
3
Les tâches Java (threads)Les tâches Java (threads)
� Les threads permettent d’exécuter des opérations en parallèles.
� Ça sert à quoi les threads ?� Les threads sont indispensables dans les
applications utilisant des IHM graphiques :� Lorsqu’un travail est exécuté dans un gestionnaire
d’événements, la pompe à message est bloquée jusqu’àla fin du traitement -> l’application semble ne réagit plus aux sollicitations de l’utilisateur.
�� Les traitements lourds doivent être fait dans des Les traitements lourds doivent être fait dans des tâches paralltâches parall èèlement lement àà la gestion de lla gestion de l ’’ IHMIHM
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
4
ÉÉtats dtats d’’une tâcheune tâche
CREE
PRÊT(Actif)
EXECSUSP
fin tâche
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
5
Commutation des tâchesCommutation des tâches� Application comportant deux tâches avec le même niveau de priorité
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
6
Ordonnancement des tâchesOrdonnancement des tâches
� Plusieurs politiques d’ordonnancement sont possibles� Politiques d'ordonnancement à priorité circulaire
� Politiques d'ordonnancement à priorité pure
� Politiques d'ordonnancement à priorité mixte� Politiques d'ordonnancement à priorité mixte et vieillissement des
tâches
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
7
Politiques d'ordonnancement Politiques d'ordonnancement àà prioritprioritéé circulairecirculaire
16
0609
CPU
tâches actives
tâches éligibles
tâchessuspendues
tâchesterminées
file des tâches actives
02 04 03
0810
file des tâches suspendues
Crée
qt
fin tâche
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
8
Politiques d'ordonnancement Politiques d'ordonnancement àà prioritprioritéé purepure
08
04
10
07
03
0609
CPU
tâches actives
tâches éligibles
tâchessuspendues
tâchesterminées
file des tâches actives
file des tâches suspenduesP
riorités
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
9
Politiques d'ordonnancement Politiques d'ordonnancement àà prioritprioritéé mixtemixte
16
0609
CPU
tâches actives
tâches éligibles
tâchessuspendues
tâchesterminées
file des tâches actives
02 04 03
12 05
11 07 13
0810
file des tâches suspendues
Priorité
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
10
La classe La classe Thread : Thread : ConstructeursConstructeurs
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
11
La classe La classe ThreadThread� Principales méthodes
� static Thread currentThread() : retourne la référence du thread courant.
� String getName() : retourne le nom de la tâche.� int getPriority() : retourne la priorité de la tâche.� void setPriority() : fixe la priorité de la tâche.� static Thread currentThread() : retourne la référence du
thread courant.� void interrupt() : relance une tâche suspendue (en sommeil)� static void sleep(long ms) : suspend la tâche durant ms
millisecondes.� void start() : démarre la tâche
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
12
Démarrage d’un thread� Méthode start() :
� crée les ressources système nécessaires pour l’exécution du thread,
� rend éligible le thread et l’ordonnance. � Si le thread a la priorité maximale la méthode
run() est lancée.� Après le retour de la méthode start(), le
thread s’exécute et se trouve dans l’état exécutable.
� On peut modifier l’ordonnancement par un mécanisme de priorité.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
13
CrCrééer un threader un thread
� Deux méthodes :� Sous classer la classe Thread et
surcharger la méthode run� Implémenter l’interface Runnable
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
14
Sous classer la classe Sous classer la classe ThreadThread
Java attribue automatiquement un nom de la forme Thread-n, où n =[0.. …] On peut également attribuer un nom personnalisé avec la méthode setName(String)Le thread
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
15
Instancier les ThreadsInstancier les ThreadsProvoque l’exécution de la méthode run() (lance le thread)
Exemple 38-Thread1
retour vers serveur socket multitâche
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
16
Implémenter de l’interface Runnable
� Si une classe dérive d’une autre classe que Thread, par exemple, Applet, il faut utiliser l’interface Runnable pour créer des threads.� Cette interface sert à ajouter le support des
threads aux classes qui ne dérivent pas de la classe Thread.
� Fourni une seule méthode, la méthode run()
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
17
Implémenter de l’interface Runnable: exemple
getName n’est plus disponible directement il faut utiliser la méthode statique currentThread()
Créer un objet runnable
Instancier un Thread avec cet objet
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
18
Ordonnancement des threads Ordonnancement des threads dans Javadans Java
� Java emprunte la politique d’ordonnancement du système d’exploitation hôte.
� Lorsqu’un thread Java est créé, il hérite sa priorité du thread qui le crée.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
19
DDééfinition des prioritfinition des prioritééss� setPriority(int) permet de la priorité d’un
thread.� Les priorités des threads sont représentées par
des valeurs entières comprises entre MIN_PRIORITY et MAX_PRIORITY (constantes de la classe Thread).
� L’ordonnancement utilisé est l'ordonnancement à priorité mixte (si le système le supporte)
� Un thread peut céder sont quantum de temps en temps en appelant la méthode yield().
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
20
Suspension d'un threadSuspension d'un thread� Un thread se bloque dans
l'attente d'une fin d'opération entrée-sortie. Lorsque l'opération E/S se termine le processeur est prévenu par un signal électrique venant du périphérique.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
21
Suspendre un threadSuspendre un thread
� sleep() : (méthode statique de la classe Thread) permet de spécifier un nombre de secondes et de nanosecondes pendant lesquelles le thread ne s’exécute pas.
� wait() : cette méthode oblige le thread en cours à attendre que la condition spécifiée soit remplie.� un autre objet doit relancer le thread en
attente (avec notify() ou notifyAll())
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
22
Se synchroniser sur la fin un Se synchroniser sur la fin un threadthread� join() permet à thread d’attendre la fin de
l’exécution d’un autre thread.� On appelle cette méthode pour le thread attendu.
On peut préciser un délai en passant à la méthode un paramètre exprimé en millisecondes.
� La méthode join() attend sur le thread jusqu’à ce que le délai soit écoulé ou que le thread soit terminé. Cette méthode fonctionne en conjonction avec la méthode isAlive(). isAlive() renvoie true si le thread a été démarré et non stoppé.
� Un thread se bloque sur une opération entrée-sortie.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
23
Stopper un threadStopper un thread
� stop() permet d’arrêter l’exécution d’un thread. A ne pas utiliser
� Pour stopper un thread, terminer la méthode run() avec un boucle finie ou tester une condition en début de la boucle du thread. Cette condition sera mise à jour par un autre thread.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
24
ProblProblèèmes posmes poséé par les accpar les accèès s concurrentsconcurrents
void TacheB(void){
...factorielle(3);...
}
void TacheA(void){
...factorielle(5);...
}
static int fac;int factorielle(int n){
fac = 1;while ( n != 1 ) {fac = fac * n;n--;
}return ( fac );
}
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
25
Sections critiquesSections critiques� Une section critique est une zone de programme où
se produit un accès concurrent et dont le résultat des traitements et fonction de l’ordonnancement des tâches ou des processus.
� Un programme multitâche doit absolument verrouiller l’accès aux sections critiques en en autorisant l’accès à une seule tâche à la fois.
� La multiplicité des sections critiques produit à un code peu efficient du fait des appels destiné àverrouiller les sections critiques.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
26
Verrouillage des section Verrouillage des section critiquescritiques
� Objets utilisés pour verrouiller les sections critiques� Sémaphores� Verrous
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
27
Les sLes séémaphoresmaphores� Les sémaphores ont été proposés pour la première fois
en 1965 par E. W. Dijkstra. Dijkstra propose de compter le nombre de tâches suspendues à l'aide d'une variable appelée sémaphore.
� Un sémaphore est constitué d'un entier s signé pouvant prendre des valeurs positives, négatives ou nulles et d'une file d'attente mémorisant les contextes des tâches suspendues. L'accès à la variable s est atomique.
� Deux primitives permettent de manipuler le sémaphore : P(s) et V(s).
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
28
Les sLes séémaphores (2)maphores (2)
Code atomique
Code atomique
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
29
ImplImpléémentation des smentation des séémaphores maphores dans Javadans Java
� Les sémaphores sont définis dans le package java.util.concurrent
� Classe Semaphore� Semaphore(int init) : constructeur
spécifiant la valeur initiale du sémaphore.� void acquire() : opération P(s)
� void release() : opération V(s)
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
30
Verrouillage des section critiques Verrouillage des section critiques àà l'aide des sl'aide des séémaphoresmaphores� Il faut initialiser le sémaphore à 1.
static Semaphore mutex = new Semaphore(1);// ... // Début de section critiquetry{mutex.acquire(); // ... Section critique
}catch (InterruptedException e){
e.printStackTrace();}// Fin section critique mutex.release();
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
31
ImplImpléémentation des verrous dans mentation des verrous dans JavaJava
� Les verrous sont définis dans le package java.util.concurrent.locksL'interface Lock fourni les méthodes permettant de verrouiller une section critique. Ces méthodes sont implémentées dans la classe ReentrantLock.
� Principales fonctions membres de l'interface Lock� lock() : verrouille le code qui suit� unlock() : déverrouille la section de code
précédente
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
32
Verrouillage des section critiques Verrouillage des section critiques àà l'aide des verrousl'aide des verrous
static Lock verrou = new ReentrantLock();
// ...
// Début de section critique
verrou.lock();
// ... section critique
verrou.unlock();
// Fin de section critique
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
33
ModModèèles d'les d'ééchange de donnchange de donnééee
� L'exclusion mutuelle des sections critiques autorise un mécanisme d'échange rudimentaire. � Dans ce type d'échange, il n'y a aucune
synchronisation entre les protagonistes. Le seul service fourni par l'exclusion mutuelle est la garantie qu'une donnée est lue ou écrite de façon atomique
� Lorsqu'on désire synchroniser les échanges entre protagonistes deux modèles sont utilisés :� Le modèle producteur-consommateur� Le modèle lecteur-rédacteur
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
34
ModModèèle producteurle producteur--consommateurconsommateur
� Ce modèle est la base de nombreux échanges de données que ce soit au cœur d'un système d'exploitation ou au sein d'applications. Son importance est telle que la plupart des noyaux fournissent directement ce type d'échange.
� Les règles de production et de consommation sont les suivantes :� Une donnée ne peut être consommée que si elle a été produite,� Une donnée ne peut être produite que si la donnée précédente a
été consommée,� On distingue deux sous modèles : le modèle ne gérant
pas de stocks et le modèle gérant des stocks
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
35
Producteur consommateur sans Producteur consommateur sans stocksstocks
� Le pseudo code ci-dessous illustre ce modèle. Les taches producteur et consommateur s'exécutent de façon concurrentes.
Tache consommateur(){while (true){
P(cons);consommer(d);V(prod);
}}
DONNEE d;Semaphore prod(1);Semaphore cons(0);
Tache producteur(){while (true){
P(prod);d = produire();V(cons);
}}
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
36
Producteur consommateur avec Producteur consommateur avec stocksstocks
� Le pseudo code ci-dessous illustre ce modèle. � Les taches producteur et consommateur s'exécutent de façon
concurrentes. Les données sont mémorisées dans une fifo comportant 100 emplacements.
� Le sémaphore prod gère la place disponible dans la fifo.
Tache consommateur(){
while (true){
P(cons);consommer(file.get());V(prod);
}}
Fifo file = new Fifo(100);Semaphore prod(100);Semaphore cons(0);
Tache producteur(){
while (true){
P(prod);file.add(produire());V(cons);
}}
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
37
ImplImpléémentation du modmentation du modèèle producteur le producteur consommateur dans Javaconsommateur dans Java
� Vu son importance, ce modèle est directement implémentédans Java dans les classes concrètes :ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue
� ArrayBlockingQueue est une fifo construite avec un vecteur.� LinkedBlockingQueue est une fifo construite avec une liste liée.� PriorityBlockingQueue est une fifo à priorité.
� Toutes ces classes implémentent l'interface Queue.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
38
Producteur consommateur Producteur consommateur implimpléémentmentéé dans Javadans Java
� Le code ci-dessous illustre ce modèle. La gestion des sémaphores est directement effectuée dans l’objet LinkedBlockingQueue
void consommateur(){while (true){
consommer(file.poll());}
}
void producteur(){while (true){file.offer(produire());
}}
Queue file = new LinkedBlockingQueue ();// ...
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
39
ModModèèle lecteur le lecteur -- rréédacteurdacteur� Le modèle lecteur - rédacteur fait appel à
plusieurs rédacteurs et plusieurs lecteurs simultanés.
� C’est le modèle de base dans les applications de type client serveur. Il se conforme aux règles suivantes :� Une donnée peut être lue simultanément par plusieurs
lecteurs sans consommation de celle-ci.� Un seul rédacteur à la fois peut modifier une donnée.� Lorsqu'un rédacteur est actif, tous les lecteurs sont
interdits de lecture.� Lorsqu'un ou plusieurs lecteurs sont actifs tous les
rédacteurs sont interdit d'écriture.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
40
Synchronisations des threadsSynchronisations des threads
� Problème posé : Il s’agit de synchroniser plusieurs tâches entre elles.
� Deux types de mécanisme peuvent être utilisés :� Mécanismes de synchronisation directs : ils
désignent directement la tâche à synchroniser� Mécanismes de synchronisation indirects :
désignent la tâche à synchroniser à travers un objet de synchronisation.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
41
Synchronisation Synchronisation àà l'aide de l'aide de sséémaphores (2)maphores (2)
void TacheT(void){
...V(S);...
}
Semahore s=0;
void TacheASynchroniser(void){...P(s)...
}
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
42
Synchronisation Synchronisation àà l'aide de l'aide de sséémaphoresmaphores
� Les sémaphores sont utilisés de façon suivante :� Une tâche (logicielle) lance une opération E/S
puis se suspend en appelant la primitive P(s)avec s initialisé à 0.
� Lorsque l'opération E/S est terminée, le périphérique concerné lance une tâche matérielle (programme d'interruption) qui effectue la primitive V(s). La tâche initiatrice le l'opération E/S se trouve relancée.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
43
Synchronisation par Synchronisation par rendezrendez--vousvous
� La synchronisation par rendez-vous permet de résoudre de façon simple la synchronisation d'un nombre connu de tâches. La puissance de mécanisme fait qu'il est incorporé de façon native dans le langage ADA et existe également dans Java.
� Les rendez-vous permettent de résoudre de nombreux problèmes de synchronisation. Supposons par exemple, que plusieurs tâches travaillent sur certaines parties d'un calcul. Lorsque toutes les parties sont prêtes, il faut combiner les résultats : les tâches doivent donc se donner rendez-vous. Le mécanisme utilisé est le suivant :� Un objet rendez-vous est instancié avec le nombre de tâches devant se
synchroniser� Chaque tâche arrivant au point de synchronisation se signale avec une
requête de l’objet rendez-vous et se suspend.� La dernière tâche arrivant au point de synchronisation en se signalant
relance toutes les autres.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
44
Synchronisation par Synchronisation par rendezrendez--vous dans Javavous dans Java
� La classe CyclicBarrier implémente la technique du rendez-vous. La mise en œuvre est la suivante :1. Initier le rendez-vous avec le nombre de tâches.CyclicBarrier rdv = new CyclicBarrier(nTask);On peut également spécifier une action a effectuer lorsque le rendez-vous est réalisé :CyclicBarrier rdv =new CyclicBarrier(nTask,Action);// Action est une classe implémentant l’interface Runnable
2. Poser le rendez-vous :rdv.await();On peut borner la durée du rendez-vous :rdv.await(100.TimeUnit.MILLISECONDS);
3. Lorsque le rendez-vous est effectué l'objet CyclicBarrier peut être réutilisé.
Daniel Tschirhart : Programmation Java V1.35 (19/11/07)
45
Groupes de threadsGroupes de threads� Un groupe de threads rassemble plusieurs threads en un objet unique afin de les manipuler
tous en même temps. � Les groupes de threads sont implémentés par la classe java.lang.ThreadGroup.� Le système d’exécution place un thread dans un groupe au moment de la construction du
thread. � Le thread est placé soit dans le groupe par défaut soit dans le groupe de threads spécifié au moment
de la création du thread. � On ne peut pas placer le thread dans un nouveau groupe après que le thread a été créé.
� getThreadGroup() permet de connaître le groupe auquel appartient un thread