Cours Java boîtes à outils awt et Swing, tutoriel & guide de travaux pratiques langage Java en pdf.
Groupes de threads
Groupes de threads de l’API Java
– Les groupes de threads sont organisées en arbre. La racine de cet arbre est le groupe System (System thread group) ; son enfant est le groupe Main, qui contient la thread dite Main, exécutant la méthode main().
– Dans le groupe System, on a 4 threads démons :
– Gestionnaire d’horloge (Clock handler) Il gère les timeouts créés par des appels aux méthodes sleep() et repaint() (qui redessine le contenu d’une fenêtre).
– Thread oisive (Idle thread) C’est une thread de priorité exceptionnellement basse : 0 (en fait, on ne peut fixer la priorité d’une thread à cette valeur via la méthode setPriority()). Elle ne tourne donc que lorsque toutes les autres threads sont bloquées. Cela permet en fait au ramassemiettes de savoir quand il peut faire la chasse aux objets qui ne sont plus référencés.
– Ramasse-miettes (Garbage collector) Il inspecte les objets au sein de la machine virtuelle, teste s’ils sont toujours référencés et libère la place mémoire correspondante si ce n’est pas le cas. Par défaut, le ramasse-miettes dort pendant une seconde ; lorsqu’il se réveille, il regarde si la thread oisive est en cours d’exécution. Si oui, il suppose que le système n’a rien à faire et il commence à inspecter la mémoire ; sinon, il se rendort pendant une seconde. Le ramasse-meittes a une priorité égale à 1, tout comme la thread de finalisation.
– Thread de finalisation (Finalizer thread) Elle appelle la méthode finalize() sur les objets libérés par le ramasse-miettes. Elle tourne à priorité 1.
– Dans le groupe Main, on a 4 threads, dont 3 ne seront actives que si l’application utilise des composants graphiques (paquetages du JFC comme java.awt, etc.) :
– Thread Main (Main thread) La thread par défaut de ce groupe exécute la méthode main().
– Thread AWT-Input Ne tourne que si l’application utilise des compo-sants graphiques. Gère les entrées du système de fenêtrage sous-jacent et effectue les appels nécessaires aux méthodes de gestion d’événements de l’AWT (Abstract Window Toolkit).
– Thread AWT-Toolkit Gère les événements du système de fenêtrage sous-jacent et appelle les méthodes appropriées. Cette thread est, dans AWT 1.1, spécifique à la plateforme et se nomme AWT-Motif (sur UNIX), AWT-Windows, etc. Certaines plateformes utilisent deux threads au lieu d’une.
– Rafraîchisseur d’écran (ScreenUpdater) Gère les appels à la méthode repaint(). Lorsqu’un tel appel se produit, cette thread est prévenue et elle appelle les méthodes update() des composants concernés.
Groupe de threads ThreadGroup
– La classe ThreadGroup permet de créer un groupe de threads.
– 2 constructeurs :
– Avec un paramètre : ThreadGroup(String groupName)
– Avec deux : ThreadGroup(ThreadGroup parentObj, String groupName)
Dans les 2 formes, groupName spécifie le nom du groupe de threads. La première version crée un nouveau groupe qui a la thread courante comme parent. Dans le 2 ième forme, le parent est spécifié par parentObj.
Exemple de groupe de threads
– L’exemple suivant liste (méthode listAllThreads() les threads (et leurs groupes) s’exécutant.
– La méthode listAllThread() utilise currentThread() (de la classe Thread) pour obtenir la thread courante, et utilise getThreadGroup() pour trouver le groupe de cette thread.
– Elle utilise ensuite getParent() de ThreadGroup pour se déplacer dans la hiérarchie des groupes de threads jusqu’à trouver le groupe racine, qui contient tous les autres groupes.
– La méthode listAllThreads() appelle ensuite la méthode privée list_group() de ThreadLister pour afficher le contenu du groupe de threads racine, et pour afficher récursivement le contenu de tous les groupes qu’elle contient.
– La méthode list_group(), et la méthode print_thread_info() qu’elle appelle, utilisent diverses méthodes de Thread et de ThreadGroup pour obtenir des informations sur les threads et sur leurs groupes.
– Remarquez que la méthode isDaemon() détermine si une méthode est un démon ou pas. Une thread démon est censée s’exécuter en arrière-plan et ne pas se terminer. L’interpréteur Java termine lorsque toutes les threads non démon ont terminé.
import java.io.*;
import java.applet.*;
import java.awt.*;
class ThreadLister {
// Afficher des informations a propos d’une activite
private static void print_thread_info(PrintStream out, Thread t,
String indent) {
if (t == null) return;
out.println(indent + « Activite : » + t.getName() +
Priorite : » + t.getPriority() + (t.isDaemon()? » Demon »: » ») + (t.isAlive()? » »: » Non vivante »));
}
Afficher des informations a propos d’un groupe d’activite, de ses activites et groupes
private static void list_group(PrintStream out, ThreadGroup g, String indent) {
if (g == null) return;
int num_threads = g.activeCount();
int num_groups = g.activeGroupCount(); Thread[] threads = new Thread[num_threads]; ThreadGroup[] groups = new ThreadGroup[num_groups];
g.enumerate(threads, false);
g.enumerate(groups, false);
out.println(indent + « Groupe d’activites : » + g.getName() +
Priorite max : » + g.getMaxPriority() + (g.isDaemon()? » Demon »: » »));
for(int i = 0; i < num_threads; i++)
print_thread_info(out, threads[i], indent + » « ); for(int i = 0; i < num_groups; i++)
list_group(out, groups[i], indent + » « );
}
Trouver la racine du groupe d’activites et lister recursivement public static void listAllThreads(PrintStream out) {
ThreadGroup current_thread_group; ThreadGroup root_thread_group; ThreadGroup parent;
// Obtenir le groupe d’activites courant
current_thread_group = Thread.currentThread().getThreadGroup();
Aller chercher la racine des groupes d’activites root_thread_group = current_thread_group;
parent = root_thread_group.getParent();
while(parent != null) {
root_thread_group = parent;
parent = parent.getParent();
}
// Et le lister, recursivement
list_group(out, root_thread_group, « »);
}
public static void main(String[] args) { ThreadLister.listAllThreads(System.out);
}
}// class ThreadLister
public class AppletThreadLister extends Applet { TextArea textarea;
Creer une zone de texte pour y mettre les informations public void init() {
textarea = new TextArea(20, 60); this.add(textarea);
Dimension prefsize = textarea.preferredSize(); this.resize(prefsize.width, prefsize.height);
}
Effectuer l’affichage. ByteArrayOutputStream est bien utile public void start() {
ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(os); ThreadLister.listAllThreads(ps); textarea.setText(os.toString());
}
}
États d’une thread et ordonnancement
Descriptif des états d’une thread
Une thread de Java peut se trouver dans l’un des 7 états qui suivent.
– nouveau (new) Lorsqu’une nouvelle thread est créée, par exemple avec Thread th = new Thread(a);
– prêt (runnable) ou prête à s’exécuter. Lorsque la méthode start() d’une thread est appelée, cette dernière passe dans l’état prêt. Toutes les threads prêtes d’un programme Java sont organisées par la machine virtuelle en une structure de données nommée la file d’attente prête. Une thread entrant dans l’état prêt est mise dans cette file. Le code de la méthode run() sera appelé à l’exécution de la thread.
– en cours d’exécution (running) La thread se voit allouée des cycles CPU par l’ordonnanceur. Si une thread dans létat en cours d’exécution appelle sa méthode yield(), ou si elle est supplantée par une thread de priorité plus élevée, elle laisse la CPU et est remise dans la file d’attente prête, entrant dans l’état prêt.
– suspendu (suspended) Une thread prête ou en cours d’exécution entre dans l’état suspendu lorsque sa méthode suspend() est appelée. Une thread peut se suspendre elle-même ou être par une autre. De l’état suspendu, une thread ré-entre dans l’état prêt lorsque sa méthode resume() est appelée par une autre thread.
– bloqué (blocked) Une thread entre dans l’état bloqué lorsque
– elle appelle sa méthode sleep(),
– elle appelle wait() dans une méthode synchronisée d’un objet,
– elle appelle join() sur un autre objet dont la thread ne s’est pas encore terminée,
– elle effectue une opération d’entrée/sortie bloquante (comme lire à partir du clavier).
À partir de l’état bloqué, une thread ré-entre dans l’état prêt.
– suspendu-bloqué (suspended-blocked) Losqu’une thread est bloquée est suspendue par une autre thread. Si l’opération bloquante se termine, la thread entre dans l’état suspendu. Si la thread est réintégrée (resumed) avant que l’opération bloquante ne se termine, elle entre dans l’état bloqué.
– mort (dead) Une thread se termine et entre dans l’état mort lorsque sa méthode run() se termine ou lorsque sa méthode stop() est appelée.
Récapitulatif des états d’une thread
Le tableau suivant résume les différents états et les événements qui engendrent une transition d’un état à un autre
Ordonnancement
– L’ordonnaceur s’assure que la thread de plus haute priorité (ou les s’il y en a plusieurs d’égale priorité) est exécutée par la CPU.
– Si une thread de plus haute priorité entre dans la file des threads prêtes, l’ordonnanceur de threads Java met la thread en cours dans la file d’attente, pour que la prioritaire s’exécute.
– La thread en cours est dite supplantée par préemption par la thread de plus haute priorité.
– Si la thread en cours d’exécution passe la main (via yield(), est suspendue ou bloquée, l’ordonnanceur choisit dans la file d’attente prête la thread de priorité la plus élevée (ou l’une d’entre elles si elles sont plusieurs) pour être exécutée.
– Un autre aspect est le partage du temps (time slicing). Un ordre de grandeur courant pour un quantum de temps est 100ms. En temps partagé, si une thread en cours d’exécution n’a pas été stoppée, bloquée, suspendue, ne s’est pas terminée, ou n’a pas passé la main, et s’il y a d’autres threads de priorité égale dans la file d’attente prête, la CPU est réallouée à l’une d’entre elles.
– ☛ Sous Solaris 2.x, la version 1.1 du JDK n’effectue pas de partage de temps entre les threads : une thread s’exécute jusqu’à ce qu’elle se termine,
(par l’ordonnanceur) 2(d’exécution) soit stoppée, suspendue, bloquée, passe la main ou qu’une autre thread de plus haute priorité devienne prête.
– Le JDK 1.1 pour Windows 95/NT partage le temps entre les threads.
Résumé pour la création d’une thread
– Les constructeurs d’une Thread acceptent comme arguments :
– Un objet Runnable, auquel cas un start() ultérieur appelle run() de l’objet Runnable fourni. Si aucun Runnable n’est fourni, l’implantation par défaut de run() retourne immédiatement.
– Une String servant d’identificateur de la thread. N’est utile que pour le traçage ou le debugging.
– Le ThreadGroup dans laquelle la nouvelle Thread doit être placée. Si l’accès au ThreadGroup n’est pas autorisé, une SecurityException est levée.
I Threads
I.1 Modèle de threads de Java
I.2 Création et utilitaires
I.3 Synchronisation
I.4 Groupes de threads
I.5 États d’une thread et ordonnancement
II Génie logiciel appliqué
II.1 Implantation d’une pile en Java
II.2 Minimisation de couplage entre méthodes
II.3 Maximisation de cohésion des méthodes
III Programmation orientée objet en Java
III.1 Exemple 1 : balles
III.2 Exemple 2 : Flipper
III.3 Formes d’héritage
III.4 Exemple 3 : jeu de solitaire
IV Boîtes à outils awt et Swing
IV.1 Aperçu des classes
IV.2 Gestion des événements
IV.3 Gestionnaire de disposition
IV.4 Composants d’interface utilisateur spécifiquement Awt
IV.5 Un exemple
IV.6 Boîtes de dialogue
IV.7 Menus
V Classe Url
V.1 Classe URL
VI Paquetage java.net : Sockets
VI.1 Sockets : Rappels TCP/IP
VI.2 Sockets : Clients
VI.3 Sockets serveurs
VI.4 Serveurs itératifs
VI.5 Serveurs non bloquants
VI.6 Serveurs concurrents
VII Invotaion de méthodes distantes : RMI
VII.1 Notion d’invocation de méthode distante
VII.2 Sécurité – Sérialisation
VII.3 Brève description du fonctionnement des RMI
VII.4 Implantation
VII.5 Paquetage java.rmi
VII.6 Paquetage java.rmi.registry
VII.7 Paquetage java.rmi.server
Bibliographie
……….