COURS THREADING
JAVA
1
PROGRAMMATION « PARALLÈLE »
Processus = unité fonctionnelle
Code
Données
Ressources
Système d’exploitation
• Un processus est une unité d’exécution qui possède son code, son espace mémoire et un accès à des ressources gérées par le système d’exploitation
• La vie d’un processus est gérée par d’exploitation
le système
Exécution
Processus 1
Processus 2
Système d’exploitation
Temps CPU
• La communication entre les processus s’effectue par des mécanismes offerts par le système d’exploitation
2
Inconvénients d’un processus
Un processus est coûteux en mémoire (code
+ données)
Le partage des données entre processus est
difficile à réaliser
Le lancement d’un processus est relativement lent à cause de : Sa taille, La charge du système d’exploitation
Le partage de certaines ressources systèmes
est difficile, parfois impossible
Classiquement les programmes ne possèdent qu’un seul processus !
3
THREAD ET UTILITÉ DU MULTI-THREADING
Définition :
Un Thread est un processus interne à un processus Un processus comporte un ou plusieurs Threads Les Threads d’un processus partagent son code, ses données et ses ressources mais peuvent aussi disposer de leurs données propres Les Threads d’un processus peuvent s’exécuter en parallèle (OS dépendant)
Avantages :
Légèreté (« light weight process » ou « processus léger ») grâce au partage des données (meilleures performances au lancement et en exécution) Partage des ressources systèmes du processus
Java est un langage multi-Thread , cette qualité dépend du support des Threads et du multi-Threading du système d’exploitation
4
LA CLASSE JAVA.LANG.THREAD
La classe Thread est la classe d’implémentation d’un Thread
Elle dispose de l’ensemble des services de
gestion d’un Thread :
Création et destruction Gestion de l’état Synchronisation
…
Pour bénéficier du multi-Threading, il y a deux
utilisations possibles :
1.
Sous-classer Thread car toute instance d’une sous-classe de Thread est un Thread 2. Définir une association entre la classe à
utiliser et la classe Thread
5
SOLUTION 1: SOUS-CLASSER THREAD
Exemple : class ActionDeCuisine extends Thread { private String afaire ; public ActionDeCuisine(String afaire) { this.afaire = afaire ; } public void run ( ) { for (int i=0 ; i<2 ; i++) System.out.println(afaire) ;} } class Recette { public static void main(String[ ] args) { ActionDeCuisine a1 = new ActionDeCuisine("Battre les
œufs");
ActionDeCuisine a2 = new ActionDeCuisine("Faire
Publicité
fondre le
Chocolat"); ActionDeCuisine a3 = new ActionDeCuisine("Ajouter
du sucre"); a1.start ( ) ; a2.start ( ) ; a3.start ( ) ; } }
6
RÉSULTAT
Le résultat exact de cet exemple dépend du système
d'exploitation.
Résultats possibles : Battre les œufs Faire fondre le chocolat Ajouter du sucre
Battre les œufs … Battre les œufs Faire
fondre
le chocolat
Battre les œufs Faire fondre le chocolat Ajouter du sucre
Faire fondre le chocolat Ajouter du sucre Ajouter du sucre
7
SOUS-CLASSER THREAD (SUITE)
La classe Thread
est la classe de base d’implémentation du multi-Threading dans Java. Sous–classer Thread permet de créer des classes d’objets qui pourront s’exécuter en parallèle
Les méthodes run ( ) et start ( ) :
void start ( ) Permet de demander au Thread concerné de démarrer (asynchrone : cette fonction redonne immédiatement la main pour la suite des instructions). void run ( ) Méthode à redéfinir pour décrire les actions le contenu de cette d'un Thread méthode qui représente les actions du Thread et qui sera donc exécuté après que le Thread aura été démarré par la méthode start( ) )
(c'est
8
PRINCIPE DE FONCTIONNEMENT
Un
système
d'exploitation multi-Thread affecte des tranches de temps à chaque Thread activable : il interrompt le Thread actif quand une tranche de temps est écoulée et passe le contrôle au Thread activable suivant. Le Thread initial ne reprendra donc la main que lorsque son tour reviendra, après que les autres Threads activables auront épuisé leur tranche de temps.
La durée des tranches de temps peut être très différente d'une machine à une autre, ce qui explique les différences de comportement d'un système à un autre.
9
SOLUTION 2: IMPLÉMENTER L’INTERFACE RUNNABLE
class ActionDeCuisine implements Runnable { private String afaire ; public ActionDeCuisine(String afaire) { this.afaire = afaire ; } public void run() {for (int i = 0 ; i<4 ; i++) System.out.println(afaire) ;} }
class Recette { public static void main(String[] args) { Thread a1 = new Thread (new ActionDeCuisine("Battre les
œufs")) ;
Thread a2 = new Thread (new ActionDeCuisine("Faire
fondre le Chocolat")) ;
Thread a3 = new Thread (new ActionDeCuisine(" Ajouter du
sucre")) ;
a1.start() ; a2.start() ; a3.start() ; } }
10
IMPLÉMENTER L’INTERFACE RUNNABLE (SUITE)
La classe Thread admet un constructeur qui prend en argument une instance de Runnable L’interface Runnable ne contient que la méthode run ( ) qui sera appelée lors du démarrage du Thread .
La classe qui contient le code a exécuter en l'interface
implémenter
doit
parallèle Runnable L’avantage
l’interface d’implémenter Runnable par une classe est que celle-ci peut étendre une autre classe au choix (puisque Java ne permet pas l’héritage multiple)
11
IMPLÉMENTER L’INTERFACE RUNNABLE (SUITE)
Remarques :
Lorsqu’on est dans le code de la méthode run ( ) , this retourne une référence sur l’objet dont la classe implémente Runnable (référence sur ActionDeCuisine). Si l’on veut récupérer une référence su le Thread lui-même il faut utiliser la méthode statique
static Thread currentThread ( )
la
de
On peut associer plusieurs Threads à une instance implémentant Runnable. Ils partagent tous les mêmes attributs de cette classe. Par contre toute variable créée dans la méthode run ( ) sera unique par Thread
Publicité
classe
12
CHOIX D’IMPLÉMENTATION D’UN THREAD
Sous-classer Thread Quand? Lorsque l’on ne nécessite pas une super-classe particulière,
ou que l’on a aucun besoin de partage contexte
class MaClasse extends Thread { … public void run ( ) {// redéfinition de run } … }
Utiliser Runnable Quand? Lorsque la super-classe est conceptuellement imposée
(exemple : Applet) ou qu’un partage de contexte est requis pour un nombre quelconque de Threads
class MaClasse extends Base implements Runnable { … public void run ( ) {// redéfinition de run } … }
13
LES ÉTATS D’UN THREAD
construction
start ( )
créé
actif
suspend ( )
sleep (…)
resume ( )
endormi
stop ( )
stop ( )
destruction
La méthode isAlive ( ) :
créé
actif
endormi mort
Retourne
false
true
true
false
14
LES ÉTATS D’UN THREAD (SUITE)
Créé Un Thread est créé comme n’importe quel objet Java, par appel à un constructeur. Lors de cette étape aucune autre opération que la réservation mémoire n’est effectuée
Actif Le Thread est dans cet état lorsque après la création, il est activé par start ( ) qui lance la méthode run ( ). Ou encore lorsqu’il est réactivé après s’être endormi. Il est alors ajouté à la liste des Threads actifs qui sont exécutés en temps partagé
Endormi Un Thread peut être endormi et réactivé de plusieurs manières :
sleep (long millisecondes) throws
InterruptedException endort le Thread pendant l’intervalle de temps spécifié et le réveille lorsque ce temps est écoulé
suspend ( ) endort un Thread et resume ( ) pourra alors
le réactiver
Mort
Quand la méthode run ( ) a terminé son exécution Par un appel explicite à stop ( )
15
PRIORITÉS
Principes
Un Thread A qui a une priorité supérieure à celle d’un autre Thread B est exécuté avant B. Les Threads de même priorité se partagent le temps du processeur avec un ordre indéterminé (système d’exploitation dépendant) À sa création un processus a par défaut la même priorité que le processus qui lui a donné naissance Java offre la possibilité de fixer les priorités des différents Threads d’un exécutable
Méthodes de Thread
void setPriority (int) : modifie la priorité du receveur en fonction du paramètre. Cette priorité doit être comprise entre [MIN_PRIORITY, MAX_PRIORITY] int getPriority ( ) : permet de connaître la priorité d’un Thread Le niveau de priorité « normal » est donné par la constante public static final int NORM_PRIORITY
16
PRIORITÉS (SUITE)
Le partage de temps CPU entre Threads de même
priorité est totalement dépendant du système d’exploitation
Publicité
Deux types de gestion de la ressource CPU
existent : Time-slicing : La ressource CPU est partagée équitablement entre Threads de même priorité par le système d’exploitation Préemption: Le partage de la ressource CPU doit être géré explicitement par l’utilisateur
Le Thread courant cède la ressource CPU à un autre Thread de même priorité dans les cas suivants :
Involontairement sur entrée-sortie Implicitement sur passage à l’état endormi Volontairement par appel à la méthode statique public static void yield ( ) courant de passer qui permet au Thread immédiatement la main aux autres. Cette méthode ne permet pas à un Thread de priorité inférieure de s’exécuter, seul un Thread de priorité égale peut prendre la main
17
LA MÉTHODE JOIN ( ) 1/2
Exemple : class ActionDeCuisine extends Thread { private String afaire ; public ActionDeCuisine(String afaire) { this.afaire = afaire ; } public void run ( ) { // le contenu du Thread for (int i=0 ; i<2 ; i++) { } } } class Recette { public static void main(String[ ] args) { ActionDeCuisine a1 = new ActionDeCuisine("Battre les
System.out.println(afaire) ;
œufs");
ActionDeCuisine a2 = new ActionDeCuisine("Faire fondre
le Chocolat");
ActionDeCuisine a3 = new ActionDeCuisine("Ajouter du
sucre");
a1.start() ; a2.start() ; a3.start() ; System.out.println("Mettre au four") ; } }
18
RÉSULTAT
Résultat : Mettre au four Battre les œufs Faire fondre le chocolat Ajouter du sucre Battre les œufs Faire fondre le chocolat Ajouter du sucre
19
LA MÉTHODE JOIN ( ) 2/2
public void join ( ) throws InterruptedException : bloque le thread en cours d’exécution jusqu’à ce qu’il termine son travail Exemple modifié: class Recette { public static void main(String[] args) { ActionDeCuisine a1 = new ActionDeCuisine("Battre
les œufs");
ActionDeCuisine a2 = new ActionDeCuisine("Faire
fondre le Chocolat");
ActionDeCuisine a3 = newActionDeCuisine("Ajouter
du sucre"); a1.start( ) ; a2.start( ); a3.start( ) ; try {a1.join( ); a2.join( ); a3.join( ); } catch (InterruptedException e) { } System.out.println("Mettre au four") ; } }
20
RÉSULTAT
Résultat : Battre les œufs Faire fondre le chocolat Ajouter du sucre Battre les œufs Faire fondre le chocolat Ajouter du sucre Mettre au four
21
EXERCICE D’APPLICATION
22
CORRECTION
public void run (){
C[i][j]=0; for (int k= 0; k< B.length; k++){ C[i][j] += A[i][k]*B[k][j]; System.out.println ( getName()+ «travaille »);
}
}
23
LANCEMENT DES THREADS
// Lancement des threads
MonThread []tabThread = new MonThread [nbThread];
int k = 0; for (int i= 0; i< C.length; i++) { for (int j= 0; j< C[i].length; j++) { tabThread[k] = new MonThread (A, B, C, i, j); tabThread[k].setName ("Thread"+k); tabThread[k].start(); k++; }
24
AFFICHAGE DU RÉSULTAT
try { for (k= 0; k<nbThread; k++) tabThread[k].join(); }
catch (InterruptedException ee){}
System.out.println("\n Matrice C"); for (int i= 0; i< C.length; i++) { for (int j= 0; j< C[i].length; j++) { System.out.print(C[i][j]+ " "); } System.out.println(); }
25