Gestion Avancée des Processus Java
Gestion Avancée des Processus Java
Gestion de processus
Emmanuel ADAM
UPHF/INSA HdF
1 Présentation
2 Création de processus
3 Transformation en processus
4 Processus et notation lambda
5 Groupe de processus
6 Planification de processus
7 Synchronisation
Principes de la synchronisation
Synchronisation de méthode
Mise en veille et Réveil de processus
8 Exemple type : les producteur et les
consommateurs
Présentation
Codes
9 Volatilité
10 Bloc synchronisé
11 Communication entre processus
E. ADAM UPHF Java Avance UPHF/INSA HdF 2 / 42
Présentation
Processus
Présentation
Un processus est un code qui s’exécute “en parallèle”
c’est-à-dire dont l’exécution n’est pas bloquante pour le reste
du programme
Exemple d’utilisation :
Longs calculs lancés en tâche de fond, permettant de lancer
d’autres calculs
L’interaction avec l’utilisateurs (les fenêtres sont des processus)
Le garbage collector (ramasse miettes) est un processus
Création de processus
classe Thread
Etendre la classe Thread permet de créer un processus
Le comportement principal du processus est à définir dans la
méthode public void run()
La méthode run() est constituée généralement d’une boucle
longue
longs calculs
attente de données (de l’interface graphique, du réseau, . . . )
Elle est appelée par la méthode start()
c l a s s UneTache e x t e n d s Thread
{
i n t nbRuns=0 ;
UneTache ( S t r i n g nom ) { s u p e r ( nom ) ; }
// r e m a r q u e : a p p e l au c o n s t r u c t e u r de Thread
p u b l i c void run ( )
{
while ( true )
{
System . o u t . p r i n t l n ( " Pour ␣ l a ␣ "+ (++nbRuns ) +" e ␣ f o i s , ␣mon
␣nom␣ e s t ␣ :␣ " + getName ( ) ) ;
Thread . y i e l d ( ) ; // p e t i t e p a u s e
} } }
p u b l i c c l a s s MaTache
{
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] )
{
UneTache t a c h e 1 = new UneTache ( " t a c h e ␣ 1 " ) ;
UneTache t a c h e 2 = new UneTache ( " t a c h e ␣ 2 " ) ;
tache1 . s t a r t () ; tache2 . s t a r t () ;
int i = 0 ;
i n t f i n = 100 ;
w h i l e ( i <f i n )
{
System . o u t . p r i n t l n ( " I c i ␣ t a c h e ␣ p r i n c i p a l e , ␣ i=" + i ) ;
i ++ ;
Thread . y i e l d ( ) ;
}
System . e x i t ( 0 ) ;
}
}
E. ADAM UPHF Java Avance UPHF/INSA HdF 6 / 42
Création de processus
Résultat de l’exécution
Pour la 1e fois, mon nom est : tache 1
Pour la 2e fois, mon nom est : tache 1
Je suis la tache principale, i=0
Pour la 1e fois, mon nom est : tache 2
Pour la 3e fois, mon nom est : tache 1
Pour la 2e fois, mon nom est : tache 2
Je suis la tache principale, i=1
Pour la 4e fois, mon nom est : tache 1
Pour la 3e fois, mon nom est : tache 2
Je suis la tache principale, i=2
....
Transformation en processus
interface Runnable
Si une classe étend une autre classe, elle ne peut étendre
Thread (pas d’héritage multiple)
La solution :
implémenter l’interface Runnable
définir la méthode run()
pour lancer un élément ‘runnable’, créer un Thread prenant en
paramètre cet élément
et démarrer ce processus
c l a s s Ob jetComptant i m p l e m e n t s R u n n a b l e
{
S t r i n g name ;
Ob jetComptant ( S t r i n g nom ) { name = nom ; }
p u b l i c void run ( )
{
i n t i =0 ;
while ( true )
{
System . o u t . p r i n t l n ( " moi ␣ " + name + " ␣ j ’ en ␣ s u i s ␣ a ␣ " + ( i
++)) ;
Thread . y i e l d ( ) ;
} } }
p u b l i c c l a s s MonRunnable
{
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] )
{
new Thread ( new ObjetComptant ( " c1 " ) ) . s t a r t ( ) ;
new Thread ( new ObjetComptant ( " c2 " ) ) . s t a r t ( ) ;
int i = 0 ;
w h i l e ( i <100)
{
System . o u t . p r i n t l n ( " J e ␣ s u i s ␣ l a ␣ t a c h e ␣ p r i n c i p a l e , ␣ i=" +
i);
i ++ ;
Thread . y i e l d ( ) ;
}
System . e x i t ( 0 ) ;
}
}
Résultat de l’exécution
moi c1 j’en suis à 0
moi c2 j’en suis à 0
Je suis la tache principale, i=0
moi c1 j’en suis à 1
moi c2 j’en suis à 1
Je suis la tache principale, i=1
moi c1 j’en suis à 2
moi c2 j’en suis à 2
Je suis la tache principale, i=2
moi c1 j’en suis à 3
moi c2 j’en suis à 3
Je suis la tache principale, i=3
....
p u b l i c c l a s s MonRunnable {
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
Thread p1 = new Thread ( ( )−>{ f o r ( i n t i =0 ; i ++<5 ; ) { System .
o u t . p r i n t l n ( " p1−>"+i ) ; Thread . y i e l d ( ) ; } } ) ;
Thread p2 = new Thread ( ( )−>{ f o r ( i n t i =100 ; i ++<105 ; ) {
System . o u t . p r i n t l n ( " p2−>"+i ) ; Thread . y i e l d ( ) ; } } ) ;
p1 . s t a r t ( ) ; p2 . s t a r t ( ) ;
w h i l e ( p1 . i s A l i v e ( ) | | p2 . i s A l i v e ( ) ) Thread . y i e l d ( ) ;
System . e x i t ( 0 ) ;
}
}
Résultat de l’exécution
p1->0
p2->100
p1->1
p2->101
p2->102
p2->103
p2->104
p1->2
p1->3
p1->4
Ils ont fini !!!
Relation processus-groupe
Création de processus
Thread(Runnable cible) : crée un processus sur l’objet cible
Thread(Runnable cible, String nom) : crée un processus sur l’objet
cible et donne un nom
Thread(ThreadGroup groupe, Runnable cible, String nom) : crée un
processus sur l’objet cible, lui donne un nom et l’affecte à un groupe
Thread(ThreadGroup groupe, Runnable cible) : crée un processus
sur l’objet cible et l’affecte à un groupe, le nom est donné
automatiquement
Tâche planifiée
Une tâche planifiée est de type TimerTask, elle possède les
méthodes
cancel() : annule la tâche
run() : action exécutée par la tâche
scheduledExecutionTime() : retourne la prochaine date en ms à
laquelle run() va être exécutée
c l a s s M a T a c h e P l a n i f i e e e x t e n d s TimerTask
{
p u b l i c void run ( ) {
System . o u t . p r i n t l n ( L o c a l T i m e . now ( ) . f o r m a t (
D a t e T i m e F o r m a t t e r . o f P a t t e r n ( " hh :mm : s s " ) ) + " ␣−>␣
E x e c u t i o n ␣ de ␣ma␣ t a c h e " ) ;
}
Résultat de l’exécution
[Link] -> Execution de ma tache
[Link] -> Execution de ma tache
[Link] -> Execution de ma tache
[Link] -> FIN !!
Principes de la synchronisation
Principes de la synchronisation
Principes de la synchronisation
Principes de la synchronisation
Synchronisation de méthode
/∗ ∗ c l a s s e s i m p l e p o s s e d a n t une f o n c t i o n s y n c h o n i s e e ∗/
public class ClasseSynchro {
C l a s s e S y n c h r o ( ) {}
/∗ ∗ f o n c t i o n s y n c h o n i s e e :
bloque l e s processus appelants s i l e parametre est impair
l e s r e v e i l l e s i un p r o c e s s u s a r r i v e a v e c un p a r a m e t r e p a i r ∗/
public synchronized void testPair ( int i ) {
System . o u t . p r i n t l n ( Thread . c u r r e n t T h r e a d ( ) . getName ( ) + " , ␣ j e
␣ suis ␣ entre ") ;
t r y { Thread . s l e e p ( 2 0 0 0 ) ; } c a t c h ( E x c e p t i o n e1 ) { }
i f ( ( i % 2 ) != 0 )
{
System . o u t . p r i n t l n ( " l e ␣ nb ␣n ’ e s t ␣ p a s ␣ p a i r , ␣ j e ␣ mets ␣ en ␣
attente ") ;
t r y { wait () ; } catch ( I n t e r r u p t e d E x c e p t i o n e ) { }
}
e l s e System . o u t . p r i n t l n ( " l e ␣ nb ␣ e s t ␣ p a i r " ) ;
C l a s s e S y n c h r o c l a s s e S y n c h r o = new C l a s s e S y n c h r o ( ) ;
Thread p1 = new Thread ( ( )−>c l a s s e S y n c h r o . t e s t P a i r ( 3 ) , " p1 " ) ;
Thread p2 = new Thread ( ( )−>c l a s s e S y n c h r o . t e s t P a i r ( 5 ) , " p2 " ) ;
Thread p3 = new Thread ( ( )−>c l a s s e S y n c h r o . t e s t P a i r ( 4 ) , " p3 " ) ;
p1 . s t a r t ( ) ;
p2 . s t a r t ( ) ;
t r y { Thread . s l e e p ( 5 0 0 0 ) ; } c a t c h ( I n t e r r u p t e d E x c e p t i o n e ) {
e . p r i n t S t a c k T r a c e ( ) ;}
p3 . s t a r t ( ) ;
Résultat de l’exécution
p1, je suis entré
le nb n’est pas pair, je mets en attente
p2, je suis entré
le nb n’est pas pair, je mets en attente
p3, je suis entré
le nb est pair
p3 sort de la fonction
Résultat de l’exécution
p1 et p2 ne sortent jamais de la méthode run() !
ils restent endormis
→ modification pour qu’un processus ayant donné un nombre
pair réveille tous les processus mis en attente
ajout de la fonction notify() (réveille un processus)
ou de notifyAll() (réveille tous les processus)
/∗ ∗ c l a s s e s i m p l e p o s s e d a n t une f o n c t i o n s y n c h o n i s e e ∗/
public class ClasseSynchro {
C l a s s e S y n c h r o ( ) {}
/∗ ∗ f o n c t i o n s y n c h o n i s e e :
bloque l e s processus appelants s i l e parametre est impair
l e s r e v e i l l e s i un p r o c e s s u s a r r i v e a v e c un p a r a m e t r e p a i r ∗/
public synchronized void testPair ( int i ) {
System . o u t . p r i n t l n ( Thread . c u r r e n t T h r e a d ( ) . getName ( ) + " , ␣ j e
␣ suis ␣ entre ") ;
t r y { Thread . s l e e p ( 2 0 0 0 ) ; } c a t c h ( E x c e p t i o n e1 ) { }
i f ( ( i % 2 ) != 0 )
{
System . o u t . p r i n t l n ( " l e ␣ nb ␣n ’ e s t ␣ p a s ␣ p a i r , ␣ j e ␣ mets ␣ en ␣
attente ") ;
t r y { wait () ; } catch ( I n t e r r u p t e d E x c e p t i o n e ) { }
}
else {
System . o u t . p r i n t l n ( " l e ␣ nb ␣ e s t ␣ p a i r " ) ;
n o t i f y A l l () ;
Résultat de l’exécution
Cette fois à l’exécution, on obtient :
p1, je suis entré
le nb n’est pas pair, je mets en attente
p2, je suis entré
le nb n’est pas pair, je mets en attente
p3, je suis entré
le nb est pair
p3 sort de la fonction
p1 sort de la fonction
p2 sort de la fonction
c l a s s Entrepot {
private int [ ] stockage ;
p r i v a t e i n t t a i l l e , nbDeposes , n b P r i s , n b O b j e t s C o u r a n t s ;
n o t i f y A l l () ;
}
c l a s s P r o d u c t e u r e x t e n d s Thread {
/∗ ∗ l i e n v e r s l ’ e n t r e p o t ∗/
Entrepot entrepot ;
/∗ ∗ i n d i q u e s i l e p r o c e s s u s d o i t s ’ a r r e t e r ∗/
p r i v a t e boolean a r r e t = f a l s e ;
/∗ ∗ t o t a l d e s o b j e t s p r o d u i t s ∗/
p r i v a t e s t a t i c i n t nbObjets = 0 ;
/∗ ∗ no du p r o d u i t a d e p o s e r ∗/
p r i v a t e i n t noObjet = 0 ;
p u b l i c P r o d u c t e u r ( S t r i n g _nom , E n t r e p o t _ e n t r e p o t )
{ s u p e r (_nom) ; e n t r e p o t = _ e n t r e p o t ;
n o O b j e t = n b O b j e t s ++ ;}
p u b l i c void run ( )
{
// t a n t que l ’ a r r e t n ’ e s t p a s demande
while ( ! arret ) {
n o O b j e t = n b O b j e t s++ ;
// t e n t e de d e p o s e r
e n t r e p o t . depose ( noObjet ) ;
System . o u t . p r i n t l n ( getName ( ) + " ␣ :␣ j ’ a i ␣ d e p o s e ␣ l ’ o b j e t ␣ "+
noObjet ) ;
// p e t i t e p a u s e de 100ms maxi
t r y { Thread . s l e e p ( ( i n t ) ( Math . random ( ) ∗ 1 0 0 ) ) ;}
c a t c h ( I n t e r r u p t e d E x c e p t i o n e ) {}
}
}
/∗ ∗ p e r m e t de demander l ’ a r r e t du p r o c e s s u s ∗/
public void halte () { a r r e t = true ; }
}
c l a s s Consommateur e x t e n d s Thread {
/∗ ∗ l i e n v e r s l ’ e n t r e p o t ∗/
Entrepot entrepot ;
boolean a r r e t = f a l s e ;
p u b l i c void run ( ) {
// t a n t que l ’ a r r e t n ’ e s t p a s demande
while ( ! arret ) {
int obj = entrepot . preleve () ;
System . o u t . p r i n t l n ( getName ( ) + " :␣ j ’ a i ␣ ␣ l ’ o b j e t ␣ " + o b j ) ;
// p e t i t e p a u s e de 200ms maxi
t r y { Thread . s l e e p ( ( i n t ) ( Math . random ( ) ∗ 2 0 0 ) ) ; }
c a t c h ( I n t e r r u p t e d E x c e p t i o n e ) {}
} }
P r o d u c t e u r [ ] t a b P r o d = { prod1 , p r o d 2 } ;
Consommateur [ ] t a b C o n s = { c on s1 , c on s2 , c o n s 3 } ;
f o r ( i n t i = 0 ; i <t a b P r o d . l e n g t h ; i ++) t a b P r o d [ i ] . s t a r t ( ) ;
f o r ( i n t i = 0 ; i <t a b C o n s . l e n g t h ; i ++) t a b C o n s [ i ] . s t a r t ( ) ;
// f a i r e t o u r n e r l e s p r o c e s s u s 4 s e c o n d e s
t r y { Thread . s l e e p ( 4 0 0 0 ) ;} c a t c h ( I n t e r r u p t e d E x c e p t i o n e ) {}
System . o u t . p r i n t l n ( t a b ) ; }}
E. ADAM UPHF Java Avance UPHF/INSA HdF 36 / 42
Volatilité
Tube de communication
Si un processus veut envoyer une donnée à un autre processus,
il peut appeler une fonction, ou communiquer par envoi de
message
Pour cela, il faut créer un tube de communication
L’émetteur reçoit l’entrée du tube,
Le destinataire reçoit la sortie du tube.
P i p e d W r i t e r o u t = new P i p e d W r i t e r ( ) ;
P i p e d R e a d e r i n=n u l l ;
t r y { i n = new P i p e d R e a d e r ( o u t ) ; }
catch ( IOException e ) {e . printStackTrace () ; }
P i p e d W r i t e r o u t = new P i p e d W r i t e r ( ) ;
P i p e d R e a d e r i n=n u l l ;
t r y { i n = new P i p e d R e a d e r ( o u t ) ; }
catch ( IOException e ) {e . printStackTrace () ; }
f i n a l P r i n t W r i t e r s t r O u t = new P r i n t W r i t e r ( o u t ) ;
f i n a l B u f f e r e d R e a d e r s t r I n = new B u f f e r e d R e a d e r ( i n ) ;
sender . s t a r t () ;
re ce iv e r . start () ;