« Programmation Java/Processus légers et synchronisation » : différence entre les versions

Contenu supprimé Contenu ajouté
francisation
Ligne 1 :
{{Programmation Java}}
 
Les processus légers ''(threads)'', ou fils d'exécution, permettent l'exécution de plusieurs tâches en même temps.
 
== Qu'est ce qu'un threadprocessus léger ? ==
Un thread est un contexte d'exécution d'une application.
Ce thread possède sa propre pile et pointeur d'exécution.
 
Un threadprocessus léger est un contexte d'exécution d'une application.
Une application en cours d'exécution (un processus) peut avoir plusieurs threads.
Ce threadprocessus possède sa propre pile et pointeur d'exécution.
Tous les threads d'un même processus partage la même zone de données.
Ce qui veut dire que toute variable membre d'une classe est modifiable par n'importe quel thread.
Il faut donc un moyen de synchroniser l'accès aux variables (voir paragraphe "Synchronisation").
 
Une application en cours d'exécution (un processus) peut avoir plusieurs threadssous-processus léger.
Par défaut, une application possède un seul thread, créé par le système.
Tous les threadsprocessus léger d'un même processus partagepartagent la même zone de données.
Cependant, en Java, d'autres threads sont créés quand l'application utilise une interface graphique, notamment un thread gérant la boucle de lecture des messages systèmes.
Ce qui veut dire que toute variable membre d'une classe est modifiable par n'importe quel threadprocessus léger.
Il faut donc un moyen de synchroniser l'accès aux variables (voir paragraphe "''[[#Synchronisation"|Synchronisation]]'').
 
Par défaut, une application possède un seul threadprocessus léger, créé par le système.
== Thread courant ==
Cependant, en Java, d'autres threadsprocessus légers sont créés quand l'application utilise une interface graphique, notamment un threadprocessus léger gérant la boucle de lecture des messages systèmes.
En Java, tout thread est représenté par un objet de classe <code>Thread</code>.
Le thread courant est retourné par la méthode statique <code>currentThread</code> de la classe <code>Thread</code>.
 
== ThreadProcessus léger courant ==
La classe <code>Thread</code> possède quelques méthodes statiques agissant sur le thread courant :
* la méthode <code>sleep(long millis)</code> permet de suspendre le thread durant le temps donné en millisecondes;
* la méthode <code>yield()</code> permet de laisser les autres threads s'exécuter;
* la méthode <code>interrupted()</code> teste si le thread courant a été interrompu;
* la méthode <code>dumpStack()</code> affiche la pile d'appel du thread courant (debuggage).
 
En Java, tout threadprocessus léger est représenté par un objet de classe <code>Thread</code>.
Le threadprocessus léger courant est retourné par la méthode statique <code>currentThread</code> de la classe <code>Thread</code>.
 
La classe <code>Thread</code> possède quelques méthodes statiques agissant sur le threadprocessus léger courant :
== Créer un thread ==
* la méthode <code>sleep(long millis)</code> permet de suspendre le threadprocessus léger durant le temps donné en millisecondes;
La classe <code>Thread</code> peut être dérivée pour créer un autre thread.
Dans ce cas, il faut surcharger* la méthode <code>runyield()</code> pourpermet yde mettrelaisser le codeles exécutéautres parprocessus lelégers thread.s'exécuter;
* la méthode <code>interrupted()</code> teste si le threadprocessus léger courant a été interrompu ;
* la méthode <code>dumpStack()</code> affiche la pile d'appel du threadprocessus léger courant (déverminage, ou debuggage en franglais).
 
 
== Créer un threadprocessus léger ==
 
La classe <code>Thread</code> peut être dérivée pour créer un autre threadprocessus léger.
Dans ce cas, il faut surcharger la méthode <code>run()</code> pour y mettre le code exécuté par le processus léger.
 
Exemple :
Ligne 35 ⟶ 38 :
public void run()
{
System.out.println("Un nouveau threadprocessus léger");
Thread.sleep(1000); // suspendu pendant 1 seconde
System.out.println("Fin du nouveau threadprocessus léger");
}
}
Il est alors créé et démarré de la manière suivante :
MyThread myth=new MyThread();
System.err.println("Démarrer le threadprocessus léger ...");
myth.start();
System.err.println("Le threadprocessus léger est démarré.");
 
Il n'est pas toujours possible d'étendre la classe <code>Thread</code> car Java n'autorise qu'une classe de base.
Mais il est permis d'implémenterutiliser plusieurs interfaces.
L'interface <code>Runnable</code> permet de résoudre le problème.
 
Ligne 58 ⟶ 61 :
public void run()
{
System.out.println("Un nouveau threadprocessus léger");
Thread.sleep(1000); // suspendu pendant 1 seconde
System.out.println("Fin du nouveau threadprocessus léger");
}
}
Le threadprocessus léger est alors créé et démarré de la manière suivante :
MyClass myclass=new MyClass ();
Thread th=new Thread(myclass); // <-- threadprocessus léger créé
System.err.println("Démarrer le threadprocessus léger ...");
th.start();
System.err.println("Le threadprocessus léger est démarré.");
 
== Actions sur un threadprocessus léger ==
 
=== Cycle de vie d'un threadprocessus léger ===
 
Un threadprocessus léger possède différents états gérés par le système :
* état ''prêt'' : le thread est prêt à être exécuté,
* état ''suspenduprêt'' : le threadprocessus est suspenduprêt (attenteà d'uneêtre ressource)exécuté,
* état ''exécutionsuspendu'' : le threadprocessus est ensuspendu cours(attente d'exécutionune ressource),
* état ''terminéexécution'' : le threadprocessus aest achevéen soncours d'exécution ou a été interrompu.,
* état ''terminé'' : le processus a achevé son exécution ou a été interrompu.
 
=== InterruptedException ===
Cette classe d'exception est lancée par les méthodes de la classe <code>Thread</code> et celle de la classe <code>Object</code> demandant la suspension pour un temps indéterminé du thread courant (attente en général).
 
Cette classe d'exception est lancée par les méthodes de la classe <code>Thread</code> et celle de la classe <code>Object</code> demandant la suspension pour un temps indéterminé du threadprocessus léger courant (attente en général).
Cette exception est lancée quand le thread en attente est interrompu.
 
Cette exception est lancée quand le threadprocessus léger en attente est interrompu.
Capturer cette exception permet d'interrompre l'attente, et libérer des ressources pour terminer proprement.
 
=== Attendre la fin d'un threadprocessus léger ===
 
La méthode <code>join()</code> de la classe <code>Thread</code> peut être appelée pour attendre la fin d'un threadprocessus léger.
 
Exemple :
th.wait(); // InterruptedException à capturer
 
=== Interrompre un threadprocessus léger ===
 
La méthode <code>interrupt()</code> de la classe <code>Thread</code> peut être appelée pour interrompre un thread.
CetteLa méthode provoque le lancement d'une exception<code>interrupt()</code> de typela classe <code>InterruptedExceptionThread</code> quandpeut leêtre threadappelée appellepour uneinterrompre méthodeun processus d'attenteléger.
Cette méthode provoque le lancement d'une exception de type <code>InterruptedException</code> quand le processus appelle une méthode d'attente.
 
== Synchronisation ==
 
La synchronisation devient nécessaire quand plusieurs threadsprocessus léger accèdent aux mêmes objets.
 
=== mot-clé synchronized ===
 
Le mot-clé <code>synchronized</code> permet un accès exclusif à un objet.
 
Ligne 107 ⟶ 116 :
}
''... code non protégé ...''
Le code protégé n'est exécuté que par un seul threadprocessus léger à la fois, tant qu'il n'a pas terminé le bloc d'instruction.
 
Durant l'exécution de ce code protégé par un threadprocessus, un autre threadprocessus ne peut exécuter celui-ci, mais peut exécuter un autre bloc <code>synchronized</code> si celui-ci n'utilise pas le même objet et qu'il n'est pas déjà en cours d'exécution.
 
Le mot-clé <code>synchronized</code> peut également être utilisé dans la déclaration des méthodes :
Ligne 140 ⟶ 149 :
 
=== Attente et signal ===
 
Quand le mot-clé <code>synchronized</code> ne suffit pas (par exemple, permettre l'accès à deux threads simultanément au lieu d'un seul), il est possible de suspendre un threadprocessus léger et le réveiller.
 
La classe <code>Object</code> possède les méthodes suivantes :
* <code>wait()</code> suspend le threadprocessus courant jusqu'à ce que la méthode <code>notify()</code> ou <code>notifyAll()</code> de cet objet soit appelée ;
* <code>wait(long timeout)</code> suspend le threadprocessus courant jusqu'à ce que la méthode <code>notify()</code> ou <code>notifyAll()</code> de cet objet soit appelée, ou bien que le temps indiqué soit écoulé ;
* <code>notify()</code> réveille l'un des threadsprocessus en attente de cet objet,
* <code>notifyAll()</code> réveille tous les threadsprocessus en attente de cet objet.
 
Pour appeler l'une de ces quatre méthodes, il faut ''posséder'' l'objet.