Cette prise de notes est issue de la lecture du chapitre concernant les Threads du livre “Au coeur de Java 2” d’Horstmann et Cornell que je vous encourage à lire si ces quelques notes ne suffisent pas à vous rafraîchir la mémoire. L’auteur de ces notes néglige toute responsabilité contre des propos déformés ou maladroitement résumés. Reportez-vous au livre et achetez-le !
Introduction
- Un contexte différent par thread.
- Contexte : Ensemble {processeur, certains registres}
- A la différence d’un processus, un thread partage le même environnement d’exécution (partage de variables). Il est plus rapide à créer, et est moins restrictif.
- Lorsqu’on interrompt un thread, celui-ci sort de son état inactif et son marqueur passe à l’état interrompu.
- Un thread ne s’appelle pas directement par la méthode run (qui s’exécuterait dans le même thread), mais par la méthode start, qui crée alors la nouvelle tâche.
- L’appel de sleep passe le thread à l’état bloqué.
- La majorité des méthodes statiques de la classe Thread agissent sur le thread courant.
Les différents états
- Pendant un sleep
- Appel à une méthode bloquante (opération d’entrée/sortie par exemple)
- Appel à wait
- Appel à un objet vérouillé
- Appel à suspend() deprecated : risque de multi-blocage (aucun controle possible).
- fin du sleep
- opération d’entrée sortie terminée
- Réception d’un notify/notifyAll sur un wait
- L’objet est dévérouillé.
- suspend a reçu un resume() deprecated.
- Fin du run()
- Exception mettant fin au run
- stop() appelé : tue le thread en lançant l’exception ThreadDeathdeprecated : risque un endommagement des objets (aucun contrôle possible).
Interruption
- isAlive() : permet de savoir si le thread est à l’état Executable ou Bloqué.
- interrupt() : Interrompt le thread et lance une InterruptedException si (et seulement si) celui-ci était à l’état bloqué à ce moment.
- interrupted() : Permet de savoir si le thread a été interrompu, et remet le marqueur d’interruption à jour.
- isInterrupted() : simple getter sur l’état d’interruption du thread.
- join(timeout) : Attend la fin d’exécution du thread ou du timeout passé en paramètre. Génère ensuite une InterruptedException sur le thread interrompu.
Priorités
- de 1 à 5, ou plutôt de MIN_PRIORITY à MAX_PRIORITY.
- Un thread a la même priorité que son parent par défaut.
- yield() : Arrêt du thread et passage de “pouvoir” à un thread avec la priorité supérieure ou égale (et uniquement) au thread courant.
- Selon les systèmes d’exploitation, les threads natifs (utilisés par windows) sont interrompus même s’il n’existe pas d’appel à yield ou sleep pendant leur exécution, contrairement aux threads Solaris, qui peuvent bloquer toute l’application sans ces appels (threads égoïstes).
Groupes de threads
- Permettent le contrôle d’un ensemble de threads en même temps. On crée alors un new ThreadGroup(String identifiant) (possibilité d’arboresence), et on ajoute des threads au groupe par new Thread(groupe, String nomDuThread);
- On retrouve les méthodes suivantes : activeCount(), interrupt(), enumerate(), getParent(), …
La synchronisation
- L’emploi de sémaphores est adaptée au procédural mais pas au langage objet.
- On utilise un système de moniteurs créé par tony Hoare : le marqueursynchronized.
- Utilisation du mot clef final : Utilisé pour les variables qui ne changent pas après leur construction. La synchronisation est alors inutile.
- Une exception qui se produit dans une méthode synchronisée entraîne la levée du verrou (on sort de la méthode).
- Si un thread est dans une méthode verrouillée, l’accès aux autres méthodes synchronisées de l’objet est accordée directement.
- Dans les blocs synchronisés :
- un wait bloque le thread et rend le verrou.
- un notifyAll débloque mais ne réactive pas forcément l’exécution (controle de verrouillage).
- La synchronisation ralentit l’exécution du traitement.
- Possibilité de synchroniser l’accès à l’objet sans créer de méthode : le bloc synchronized(objet) {…}
Interface Runnable
- L’utilisation de cette interface permet d’utiliser un objet héritant déjà d’un autre objet (héritage unique). L’objet runnable contiendra alors un attribut thread qui sera lancé dans une méthode start(). le code exécuté sera celui de la méthode run()
Les threads démons
- Il ne servent qu’à lancer d’autres threads. Un programe se termine lorsqu’il ne reste plus que des threads démons.
Les threads graphiques
- Encore appelé Répartition des événements. Il exécute notamment les méthodes actionPerformed, paintComponent, etc.
- repaint : Programme un refresh de l’affichage
- revalidate : Permet de redessiner et de replacer un composant dont la taille, la position, ou le contenu ont changé. La version AWT : invalidate(); validate();
- Les modifications en Swing sont impossibles à partir d’autres threads que celui de la répartition des événements. On utilisera à cet effet la méthode statique EventQueue.invokeLater(Runnable) qui permet par exemple de mattre à jour le contenu d’une JList à partir d’un thread. La version invokeAndWait bloque l’exécution jusqu’à ce que la tâche soit terminée.