Accueil
Java Standard Edition
Java EE 5
Visual Basic .Net 2005
Visual C++ .Net 2005
Visual C# .Net 2005
Cours ASP .Net 2.0
Postgresql
Linux
Visual Studio 2008
ASP 3.0 Classique
Cours Javascript - DOM - DHTML
Cours Ajax
VBA
Assembleur
Perl
Membres
L'auteur du site
Nouveautés sur le site
Contacts
Plan du site
Exécution d'un programme
Les archives Jar
Les classes abstraites
Les interfaces
Les tableaux
La généricité
Les énumérations
Les classes internes
Classes anonymes et internes locales
Les threads: généralités
Les threads(2): synchronisation
E/S(1):InputStream et OutputStream
E/S(2):FileInputStream et FileOutputStream
E/S(3):Reader et Writer
E/S(4):FilterInputStream et FilterOutputStream
E/S(5):Les filtres d'octets: PrintStream
E/S(6):Les filtres d'octets: DataInputStream et DataOutputStream
E/S(7):Les filtres d'octets: BufferedInputStream et BufferedOutputStream
E/S(8):Flux de caractères: PrintWriter
E/S(9):Flux de caractères: FilterReader et FilterWriter
E/S(10):Flux de caractères: InputStreamReader, OutputStreamWriter, StreamDecoder, StreamEncoder
E/S(11):Flux de caractères: BufferedReader et BufferedWriter
E/S(12):Flux de caractères: FileReader et FileWriter
La classe String (java.lang)
Les collections: L'interface Collection(java.lang)
Les collections(2): L'interface List(java.util)
Les collections(3): AbstractCollection(java.util)
Les collections(4): AbstractList(java.util)
Les collections(5): Vector(java.util)
Les collections(6): L'interface Map(java.util)
Les collections(7): AbstractMap(java.util)
Les collections(8): HashMap(java.util)
La bibliothèque Swing en Java
Les bases de données en Java
JDBC ( Java Database Connectivity )
Les interfaces graphiques
Les fichiers de configuration en Java
INSTALLATION JAVA EE 5, JRE 6, ECLIPSE, TOMCAT, ETC SOUS LINUX
INSTALLATION JAVA EE 5, JRE 6, ECLIPSE, TOMCAT, ETC SOUS WINDOWS
Les applications Web en java
Les filtres Java (javax.servlet.Filter)
I Généralités
I.1 Le formulaire principal
I.2 Les objets créés par Visual
I.3 Les variables références
I.4 Le garbage collector
II Créer évènements
II.1 Rappel évènements
II.2 Procédure à suivre
II.2.1 Créer son EventArgs
II.2.2 Créer EmetEvent
II.2.3 Déclarations autres
I Généralités
I.1 Applications winforms
I.2 Applications MFC
I.3 Objets managés ou pas
I.4 Objets non managés
I.5 Objets managés - handle
I.6 Le top-level ^
II Créer évènements
II.1 Rappel évènements
II.2 Procédure à suivre
II.2.1 Créer son EventArgs
II.2.2 Créer EmetEvent
II.2.3 Déclarations autres
I Généralités
I.1 Puissant et Accessible
I.2 Créer ses classes
II Créer évènements
II.1 Rappel évènements
II.2 Procédure à suivre
III Les services Windows
IV Le .net remoting
V Communication Tcp avec TcpClient et TcpListener
II.2.1 Créer son EventArgs
II.2.2 Créer EmetEvent
II.2.3 Déclarations autres
I Généralités
I.1 Un EDI formidable
I.2 Inclure C# ou VB
I.3 L'objet Response
I.4 Les évènements
II ASP .net et les bdd
II.1 Essayer plusieurs fois la requête
I 2.1 Fichiers distincts
I.2.2 Avec la balise script
I.2.3 Inclure réellement
I.2.4 Avec Response.Write()
I.3.1 La méthode Response.Redirect()
I.4.1 Résoudre problème post
Installation Postgre Linux
Cours Postgresql
Le Shell Unix( Linux, Ubuntu)
Les scripts C-Shell
Programmation système Unix
Reseau Linux
Les iptables
Windows Presentation Foundation(WPF)
Le Framework 3.0
Windows Workflow Foundation(WF)
ASP 3.0 Classique
Cours Javascript - DOM - DHTML
Chat Ajax
VBA Excel 2003
Assembleur
Perl
Inscription
Liste membres
Livre d'or
Forum
Accueil
>
Java Standard Edition
>
Les threads: généralités
____________________________________________________________________________________________________
Connexion
JSE - le langage - les threads(1): généralités
Sommaire :
I) Introduction
II) Différences en thread et processus(ou process)
III) Implémentation des threads
IV) La classe Thread(java.lang)
IV.1) Création d'une classe héritant de Thread
IV.2) Démarrage du thread
IV.3) Problème d'héritage multiple
IV.3.A) L'interface Runnable (java.lang)
IV.3.B) Construire un thread avec le constructeur runnable
IV.3.C) Utilisation avec Runnable
IV.3.D) Conclusion sur Runnable
(Suite dans une autre page)
V) Les méthodes de la classe Thread
VI) Le thread de la méthode main
VII) L'erreur ThreadDeath(java.lang) levée par la méthode deprecated stop()
VIII) La synchronisation des threads
IX) Code source complet de l'exemple
IX.1) classe Main (package main)
IX.2) Classe DemonCompte (package threads)
IX.3) Classe threadVoiture (package threads)
IX.4) Classe Voiture (package vehicules)
IX.5) Classe VoitureMT (package vehicules)
X) Téléchargement de l'exemple
I) Introduction
Le langage java est multi-thread. Cela signifie que plusieurs programmes peuvent s'exécuter au même moment, en parallèle. Cela comporte des avantages, que nous ne détaillerons pas ici.
II) Différences en thread et processus(ou process)
Un processus est une application. Il possède un ou plusieurs threads.
Les applications peuvent s'exécuter en parallèle, ce qui est traité par le système d'exploitation. Chacune d'elle possède ses ressources propres, notamment la mémoire, mais aussi des ressources comme l'écran, la souris etc...
Par contre, tous les threads d'un processus utilisent les ressources de ce processus. Il y a donc partage des ressources de ce process par l'ensemble de ses threads.
III) Implémentation des threads
La JVM utilise directement les threads natifs du système d'exploitation, pour des problèmes de performances.
IV) La classe Thread(java.lang)
C'est la classe Thread qui possède toutes les fonctions "native", qui ne sont pas implémentées en java, et qui utilisent directement l'interface native du système d'exploitation.
Thread représente un thread ne faisant rien, car sa méthode run() ne fait rien.
En réalité, nous verrons plus tard que run() ne fait rien, si on a construit notre thread avec un constructeur prenant une string en argument(ce que nous fairons pour l'instant).
Il est donc indispensable de créer une classe héritant de Thread, et de redéfinir la méthode run()(une autre solution existe, avec les Runnable, que nous verrons après).
Vous l'avez compris, la méthode run() est la méthode qui doit contenir le code exécuté parallèlement.
IV.1) Création d'une classe héritant de Thread
On crée notre classe de Thread, comme dans le projet d'exemple:
package threads; public class threadVoiture extends Thread { private int vitesse; //accesseurs public int getVitesse() { return vitesse; } public void setVitesse(int vitesse) { this.vitesse = vitesse; } //constructeurs public threadVoiture(String pNom, int pVitesse) { super(pNom); this.vitesse = pVitesse; } public void run() { System.out.println("Début thread " + this.getName()); // try { for(int i=0;i<10;i++) { Thread.sleep(1000); //met en sommeil le thread courant, donc le notre System.out.println(this.getName()+":"+ ((i+1)*vitesse) + " mètres parcourus" ); } } catch (InterruptedException e) { e.printStackTrace(); return; } } }
IV.2) Démarrage du thread
Regardons maintenant le main:
public class Main { public static void doExemple1() { //Exemple 1: avec threadVoiture threadVoiture thVoitJean = new threadVoiture("thVoitJean", 100); threadVoiture thVoitPierre = new threadVoiture("thVoitPierre", 200); //Démarrage du thread System.out.println("Exemple 1: avec la classe threadVoiture"); thVoitJean.start(); thVoitPierre.start(); } /** * Essayer les exemples un par un: décommenter l'exemple voulu, et * commenter les autres. * @param args */ public static void main(String[] args) { Main.doExemple1(); //Main.doExemple2(); //Main.doExemple3(); } }
On crée d'abord un objet threadVoiture, dont le nom est thVoitJean.
Pour démarrer ce thread, on appelle sa méthode start().
Ici, on crée deux threads différents, et pour cela il est nécessaire de créer un objet Thread par thread.
L'exemple ici simule le démarrage de deux voitures, qui vont à deux vitesses différentes: l'une à 100 m/s, et l'autre à 200 m/s.
Le résultat de l'exécution est le suivant:
Début thread thVoitJean
Début thread thVoitPierre
thVoitPierre:200 mètres parcourus
thVoitJean:100 mètres parcourus
thVoitPierre:400 mètres parcourus
thVoitJean:200 mètres parcourus
thVoitPierre:600 mètres parcourus
thVoitJean:300 mètres parcourus
thVoitPierre:800 mètres parcourus
thVoitJean:400 mètres parcourus
thVoitPierre:1000 mètres parcourus
thVoitJean:500 mètres parcourus
thVoitPierre:1200 mètres parcourus
thVoitJean:600 mètres parcourus
thVoitJean:700 mètres parcourus
thVoitPierre:1400 mètres parcourus
thVoitPierre:1600 mètres parcourus
thVoitJean:800 mètres parcourus
thVoitPierre:1800 mètres parcourus
thVoitJean:900 mètres parcourus
thVoitJean:1000 mètres parcourus
thVoitPierre:2000 mètres parcourus
IV.3) Problème d'héritage multiple
On s'aperçoit que la méthode précédente ne nous permet pas d'avoir notre classe de thread qui hérite déjà d'une autre classe.
Par exemple, si on veut faire hériter notre classe threadVoiture, de la classe Voiture. On ne pourrait pas, car threadVoiture hérite déjà de la classe Thread.
De plus, on aurait voulu plutôt l'appeler VoitureMT(voiture multi-thread), car l'objet obtenu représenterait d'avantage une voiture, plutôt qu'un thread. Du point de vue du raisonnement, on voit bien un problème de l'héritage multiple: cela complique le raisonnement, car on a un objet qui représente deux réalités( ici une voiture et un thread).
Les interfaces permettent de résoudre le problème. Car l'objet qui hérite d'une classe, par exemple qui hérite de Voiture, représente toujours une voiture. Et, de plus, il possède des capacités particulières, du fait des interfaces implémentées(ici la capacité d'être démarrable). Mais, du point du vue du raisonnement, il représente toujours une voiture.
IV.3.A) L'interface Runnable (java.lang)
package java.lang; /** * The <code>Runnable</code> interface should be implemented by any * class whose instances are intended to be executed by a thread. The * class must define a method of no arguments called <code>run</code>. * <p> * This interface is designed to provide a common protocol for objects that * wish to execute code while they are active. For example, * <code>Runnable</code> is implemented by class <code>Thread</code>. * Being active simply means that a thread has been started and has not * yet been stopped. * <p> * In addition, <code>Runnable</code> provides the means for a class to be * active while not subclassing <code>Thread</code>. A class that implements * <code>Runnable</code> can run without subclassing <code>Thread</code> * by instantiating a <code>Thread</code> instance and passing itself in * as the target. In most cases, the <code>Runnable</code> interface should * be used if you are only planning to override the <code>run()</code> * method and no other <code>Thread</code> methods. * This is important because classes should not be subclassed * unless the programmer intends on modifying or enhancing the fundamental * behavior of the class. * * @author Arthur van Hoff * @version 1.26, 11/17/05 * @see java.lang.Thread * @see java.util.concurrent.Callable * @since JDK1.0 */ public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
Nous nous apercevons que l'interface Runnable comporte une seule méthode: la méthode void run().
Remarque: le abstract de run() est redondant, c'est pour garder la compatibilité avec les vieilles versions. ("For compatibility with older versions of the Java platform, it is permitted but discouraged, as a matter of style, to redundantly specify the abstract modifier for methods declared in interfaces.", site java.sun.com, chapitre sur les interfaces).
Il suffit de faire implémenter cette interface Runnable par notre classe voitureMT.
Notre objet voitureMT devient alors démarrable, on est certain qu'il possède une méthode public void run().
IV.3.B) Construire un thread avec le constructeur runnable
Un des constructeur de la classe Thread, prend un objet Runnable en paramètre.
public Thread(Runnable target)
Il faut l'utiliser, en lui passant notre objet Runnable. En fait, le constructeur va mettre l'objet Runnable dans son attribut privé appelé target. Et la méthode run() de Thread, va juste faire target.run() :
/** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * <p> * Subclasses of <code>Thread</code> should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ public void run() { if (target != null) { target.run(); } }
IV.3.C) Utilisation avec Runnable
Prenons l'exemple du projet.
On a deux classes, une mono-thread, et une multi-thread.
Chaque classe représente une voiture.
Regardons la classe Voiture, qui n'est pas multi-thread:
package vehicules; /** * Cette classe n'est pas multi-thread * @author sabri Koffler * */ public class Voiture { //attributs privés private int vitesse; //attributs privés avec accesseurs //sur la voiture private String marque; private String modele; private int nbChevaux; private int annee; //sur son propriétaire private String nomPropri; private String prenomPropri; //constructeurs public Voiture(int vitesse, String marque, String modele, int nbChevaux, int annee, String nomPropri, String prenomPropri) { super(); this.vitesse = vitesse; this.marque = marque; this.modele = modele; this.nbChevaux = nbChevaux; this.annee = annee; this.nomPropri = nomPropri; this.prenomPropri = prenomPropri; } //accesseurs public String getMarque() { return marque; } public void setMarque(String marque) { this.marque = marque; } public String getModele() { return modele; } public void setModele(String modele) { this.modele = modele; } public int getNbChevaux() { return nbChevaux; } public void setNbChevaux(int nbChevaux) { this.nbChevaux = nbChevaux; } public int getAnnee() { return annee; } public void setAnnee(int annee) { this.annee = annee; } public String getNomPropri() { return nomPropri; } public void setNomPropri(String nomPropri) { this.nomPropri = nomPropri; } public String getPrenomPropri() { return prenomPropri; } public void setPrenomPropri(String prenomPropri) { this.prenomPropri = prenomPropri; } public int getVitesse() { return vitesse; } public void setVitesse(int vitesse) { this.vitesse = vitesse; } //méthodes public void demarrer() { System.out.println("La voiture démarre"); try { for(int i=0;i<10;i++) { Thread.sleep(1000); //met en sommeil le thread courant, donc le notre System.out.println(getMarque()+" "+getModele()+":"+ ((i+1)*vitesse) + " mètres parcourus" ); } } catch (InterruptedException e) { e.printStackTrace(); return; } } public void arreter() { System.out.println("La voiture est arrêté"); } }
C'est classique: on a des attributs de la voiture, et des méthodes, comme la méthode demarrer ou arreter().
Regardons la classe VoitureMT, qui elle est multiThread.
package vehicules; /** * Remarque: la méthode Demarrer reste accessible, mais n'est * pas multi-thread: dans ce cas, on utilise la classe VoitureMT * comme si c'était la classe Voiture. * @author sabri Koffler * */ public class VoitureMT extends Voiture implements Runnable { /** * Même constructeur que celui de Voiture. * @param vitesse * @param marque * @param modele * @param nbChevaux * @param annee * @param nomPropri * @param prenomPropri */ public VoitureMT(int vitesse, String marque, String modele, int nbChevaux, int annee, String nomPropri, String prenomPropri) { super( vitesse, marque, modele, nbChevaux, annee, nomPropri, prenomPropri); } /** * Implémentation de run() pour l'interface Runnable. * Noter que le code source de demarrer n'a pas été du tout reprogrammé. * La programmation est donc faite de manière séquentielle. */ public void run() { super.demarrer(); } }
VoitureMT hérite de Voiture, et représente toujours une voiture.
Il n'y a pratiquement rien à mettre dans cette classe, juste la méthode run() à créer, qui ne fait qu'appeler la méthode demarrer de la classe mère.
Remarquons que demarrer est toujours accessible, mais n'est pas multi-thread: dans ce cas, on utilise la classe VoitureMT comme si c'était la classe Voiture.
A présent, voici le main:
package main; import threads.threadVoiture; import vehicules.Voiture; import vehicules.VoitureMT; public class Main { public static void doExemple2() { //Exemple 2: avec VoitureMT System.out.println("Exemple 2: avec les classes Voiture et VoitureMT"); //on crée des voitures avec la classe Voiture, qui n'est pas multithread Voiture voitJean = new Voiture(100, "Renault", "Megane", 7, 2005, "Jean", "Dupont"); Voiture voitPierre = new Voiture(200, "Peugeot", "206", 9, 2007, "Pierre", "Martin"); voitJean.demarrer(); voitPierre.demarrer(); //Ci-dessus, la voiture de Pierre ne démarre que quand la voiture de Jean est //arrivée. Les voitures roulent l'une après l'autre, et non pas //en même temps System.out.println("Voitures Multi-threads"); VoitureMT voitMTJean = new VoitureMT(100, "Renault", "Megane", 7, 2005, "Jean", "Dupont"); VoitureMT voitMTPierre = new VoitureMT(200, "Peugeot", "206", 9, 2007, "Pierre", "Martin"); Thread thJean = new Thread(voitMTJean); Thread thPierre = new Thread(voitMTPierre); thJean.start(); thPierre.start(); } /** * Essayer les exemples un par un: décommenter l'exemple voulu, et * commenter les autres. * @param args */ public static void main(String[] args) { //Main.doExemple1(); //Main.doExemple2(); Main.doExemple3(); } }
On utilise d'abord la classe Voiture: les deux voitures ne roulent pas en même temps. La deuxième voiture démarre lorsque la première est arrivée.
Puis on utilise la classe VoitureMT. On crée deux voitures de la classe VoitureMT.
Puis on crée deux threads, thJean et thPierre, car nous aurons besoin de deux threads pour exécuter chaque voiture.
Quand on crée chaque thread, on donne au constructeur notre objet VoitureMT, qui est un Runnable.
Il ne reste plus qu'à démarrer chaque thread, avec start().
Les deux voitures démarrent et roulent en même temps.
Voici le résultat de l'exécution pour les voitures multi-threads:
Voitures Multi-threads
La voiture démarre
La voiture démarre
Peugeot 206:200 mètres parcourus
Renault Megane:100 mètres parcourus
Peugeot 206:400 mètres parcourus
Renault Megane:200 mètres parcourus
Peugeot 206:600 mètres parcourus
Renault Megane:300 mètres parcourus
Peugeot 206:800 mètres parcourus
Renault Megane:400 mètres parcourus
Peugeot 206:1000 mètres parcourus
Renault Megane:500 mètres parcourus
Peugeot 206:1200 mètres parcourus
Renault Megane:600 mètres parcourus
Peugeot 206:1400 mètres parcourus
Renault Megane:700 mètres parcourus
Peugeot 206:1600 mètres parcourus
Renault Megane:800 mètres parcourus
Peugeot 206:1800 mètres parcourus
Renault Megane:900 mètres parcourus
Peugeot 206:2000 mètres parcourus
Renault Megane:1000 mètres parcourus
IV.3.D) Conclusion sur Runnable
- On n'a pas eu à réécrire le code de la méthode demarrer(). La programmation multi-thread a été une programmation séquentielle.
- On aurait pu utiliser le même objet Runnable pour les deux threads, ici la même VoitureMT. Dans ce cas, les deux threads auraient partagé les mêmes ressources. Ceci pose des problèmes de modifications concurrentes, et donc nécessite une synchronisation. Nous parlerons de cela par la suite.
V) Les méthodes de la classe Thread
VI) Le thread de la méthode main
VII) L'erreur ThreadDeath(java.lang) levée par la méthode deprecated stop()
VIII) La synchronisation des threads
IX) Code source complet de l'exemple
IX.1) classe Main (package main)
IX.2) Classe DemonCompte (package threads)
IX.3) Classe threadVoiture (package threads)
IX.4) Classe Voiture (package vehicules)
IX.5) Classe VoitureMT (package vehicules)
X) Téléchargement de l'exemple
RETOUR HAUT