# Programmation Java/Processus légers et synchronisation

* Introduction
* La notion de machine virtuelle
* Installation
** NetBeans
** Eclipse
** Visual Studio Code
* Bases du langage
** Premier programme
** Commentaires
** Types de base
** Opérateurs
** Conditions
** Bloc de portée
** Itérations
** Tableaux
* Les classes en Java
** Membres
** Modificateurs d'accès
** Héritage
** Encapsulation
** Polymorphisme
** Classes abstraites
** Interfaces
** Classes internes
** Transtypage
** Types génériques
** Instanciation et cycle de vie
** « this »
** Objets comparables et clés
** Énumérations
** Exceptions
** Packages
* Classes de base
** Collections
** Nombre de taille arbitraire
** Tags Javadoc
** Annotations
** Entrées sorties
** Threads et synchronisation
** Méthodes natives
** Réflexion
** Regex
** JUnit
* Conclusion
* Exemples en Java
** Générer un carré magique
** Générer un triangle de Sierpiński
** XML
** Swing
*** Un premier exemple
*** Formulaire avec boutons sur image
*** Calcul de somme
*** Calcul de distance
* Annexes
** Les outils de base fournis avec le Java Development Kit
** Créer une archive Java
** Paramétrer la JVM
** Liste des mots réservés
** Débogage
** Java et les autres langages
* Introduction
* La notion de machine virtuelle
* Installation
** NetBeans
** Eclipse
** Visual Studio Code
* Bases du langage
** Premier programme
** Commentaires
** Types de base
** Opérateurs
** Conditions
** Bloc de portée
** Itérations
** Tableaux
* Les classes en Java
** Membres
** Modificateurs d'accès
** Héritage
** Encapsulation
** Polymorphisme
** Classes abstraites
** Interfaces
** Classes internes
** Transtypage
** Types génériques
** Instanciation et cycle de vie
** « this »
** Objets comparables et clés
** Énumérations
** Exceptions
** Packages
* Classes de base
** Collections
** Nombre de taille arbitraire
** Tags Javadoc
** Annotations
** Entrées sorties
** Threads et synchronisation
** Méthodes natives
** Réflexion
** Regex
** JUnit
* Conclusion
* Exemples en Java
** Générer un carré magique
** Générer un triangle de Sierpiński
** XML
** Swing
*** Un premier exemple
*** Formulaire avec boutons sur image
*** Calcul de somme
*** Calcul de distance
* Annexes
** Les outils de base fournis avec le Java Development Kit
** Créer une archive Java
** Paramétrer la JVM
** Liste des mots réservés
** Débogage
** Java et les autres langages
[ Modifier le sommaire ]
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 processus léger ?

Un processus léger est un contexte d'exécution d'une application. Ce processus possède sa propre pile et pointeur d'exécution.
Une application en cours d'exécution (un processus) peut avoir plusieurs sous-processus léger. Tous les processus légers d'un même processus partagent la même zone de données. Ce qui veut dire que toute variable membre d'une classe est modifiable par n'importe quel processus léger. Il faut donc un moyen de synchroniser l'accès aux variables (voir paragraphe Synchronisation).
Par défaut, une application possède un seul processus léger, créé par le système. Cependant, en Java, d'autres processus légers sont créés quand l'application utilise une interface graphique, notamment un processus léger gérant la boucle de lecture des messages systèmes.

## Processus léger courant

En Java, tout processus léger est représenté par un objet de classe Thread. Le processus léger courant est retourné par la méthode statique currentThread de la classe Thread.
La classe Thread possède quelques méthodes statiques agissant sur le processus léger courant :
* la méthode sleep(long millis) permet de suspendre le processus léger durant le temps donné en millisecondes;
* la méthode yield permet de laisser les autres processus légers s'exécuter;
* la méthode interrupted teste si le processus léger courant a été interrompu ;
* la méthode dumpStack affiche la pile d'appel du processus léger courant (déverminage, ou débuggage en franglais).

## Créer un processus léger

La classe Thread peut être dérivée pour créer un autre processus léger. Dans ce cas, il faut surcharger la méthode run pour y mettre le code exécuté par le processus léger.
Exemple :
Il est alors créé et démarré de la manière suivante :
Il n'est pas toujours possible d'étendre la classe Thread car Java n'autorise qu'une classe de base. Mais il est permis d'utiliser plusieurs interfaces. L'interface Runnable permet de résoudre le problème.
Par défaut, la méthode run de la classe Thread appelle la méthode run de l'interface Runnable passé en paramètre du constructeur.
Exemple :
Le processus léger est alors créé et démarré de la manière suivante :

## Actions sur un processus léger
### Cycle de vie d'un processus léger

Un processus léger possède différents états gérés par le système :
* état prêt : le processus est prêt à être exécuté,
* état suspendu : le processus est suspendu (attente d'une ressource),
* état exécution : le processus est en cours d'exécution,
* é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 Thread et celle de la classe Object demandant la suspension pour un temps indéterminé du processus léger courant (attente en général).
Cette exception est lancée quand le processus 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 processus léger

La méthode join de la classe Thread peut être appelée pour attendre la fin d'un processus léger.
Exemple :

### Interrompre un processus léger

La méthode interrupt de la classe Thread peut être appelée pour interrompre un processus léger. Cette méthode provoque le lancement d'une exception de type InterruptedException quand le processus appelle une méthode d'attente.

## Synchronisation

La synchronisation devient nécessaire quand plusieurs processus légers accèdent aux mêmes objets.

### mot-clé synchronized

Le mot-clé synchronized permet un accès exclusif à un objet.
La syntaxe est la suivante :
Le code protégé n'est exécuté que par un seul processus 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 processus léger, un autre processus léger ne peut exécuter celui-ci, mais peut exécuter un autre bloc synchronized 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é synchronized peut également être utilisé dans la déclaration des méthodes :
est équivalent à :
Pour une méthode statique (méthode de classe) :
est équivalent à :

### Attente et signal

Quand le mot-clé synchronized ne suffit pas (par exemple, permettre l'accès à deux processus légers simultanément au lieu d'un seul), il est possible de suspendre un processus léger et le réveiller.
La classe Object possède les méthodes suivantes :
* wait suspend le processus courant jusqu'à ce que la méthode notify ou notifyAll de cet objet soit appelée ;
* wait(long timeout) suspend le processus courant jusqu'à ce que la méthode notify ou notifyAll de cet objet soit appelée, ou bien que le temps indiqué soit écoulé ;
* notify réveille l'un des processus en attente de cet objet,
* notifyAll réveille tous les processus en attente de cet objet.
Pour appeler l'une de ces quatre méthodes, il faut posséder l'objet. Ce qui signifie utiliser l'instruction synchronized. Dans le cas contraire, l'exception suivante est levée :
Exemple :
Comme ces méthodes sont définies dans la classe Object, il est possible de les utiliser avec n'importe quel type d'objet, et donc les chaînes de caractères et les tableaux.

## Une bibliothèque spécialisée

Il est très courant d'être amené à protéger l'accès à une variable pour juste par exemple, une incrémentation sous condition, comparer et échanger deux valeurs, chercher et ajouter. Ces méthodes sont qualifiées d'atomiques. La solution la plus efficace consiste à utiliser les classes de la bibliothèque java.util.concurrent. Ces classes disposent de méthodes considérées comme toujours plus rapides en mode multi-thread que celles d'une liste synchronisée, prenons par exemple le cas des listes :
Un autre thread ne peut pas effectuer de modification entre containsKey et put, du fait du verrou pris par l'instruction synchronized sur l'objet map. Mais cette solution est en réalité peu efficace car elle contraint le plus souvent à protéger tous les accès à la liste, en lecture comme en écriture, alors que les accès en lectures multiples n'ont pas à être bloquants, seuls ceux en écriture devant l'être. La classe ConccurentHashMap possède un putIfAbsent. Il est possible de réimplanter cette caractéristique via la synchronisation sur deux valeurs, mais les classes fournies par java.util.concurrent sont, elles, exemptes de bugs.
Si la classe de liste ne vous satisfait pas, la pose de verrou via la classe ReentrantReadWriteLock est extrêmement simple.