Page d'accueilFindIt !ContactLes exceptionsLes classes internes

Le langage JavaTM

Table des matièresHierarchie des classes

CJava

 Les threads

Définition d'un thread
La création d'un thread
Les états d'un thread
La synchronisation des threads
La classe Thread

 

Définition d'un thread

L'environnement de la Machine Virtuelle Java est multi-threads. L'équivalent de thread pourrait être tâche en français, mais pour éviter la confusion avec la notion de système multitâches, on emploiera le mot thread plutôt que tâche. Le fait que Java permettent de faire tourner en parallèle plusieurs threads lui donne beaucoup d'intérêt : Ceci permet par exemple de lancer le chargement d'une image sur le Web (ce qui peut prendre du temps), sans bloquer votre programme qui peut ainsi effectuer d'autres opérations.
Pour vous montrer les possibilités du multi-threading voici une applet qui peut lancer trois horloges tournant en parallèle (au passage, voici une démonstration de réutilisation de la classe TimeCounter déjà utilisée au premier chapitre).

Applet MultiTime

!

Ne confondez pas le multi-threads avec le traitement événementiel grâce à un timer, dont le résultat rendrait la même chose. Dans cette applet, il y a réellement trois threads différents qui gèrent chacun une horloge mise à jour à intervalle régulier. La mise à jour n'est pas déclenchée suite à un événement du type WM_TIMER émis régulièrement par le gestionnaire de fenêtres.


Plusieurs aspects des threads sont à étudier pour bien comprendre leur fonctionnement et leur utilisation : la gestion par la Machine Virtuelle Java pour répartir le temps d'exécution entre les différents threads, la manière de créer un thread, les différents états possibles d'un thread, et la synchronisation entre threads pour le partage de données.

C

L'environnement Java est multi-threads, et le langage permet d'utiliser cette fonctionnalité pour créer vos propres threads, et synchroniser des threads qui partagent des données.

Le partage du temps entre threads

Comment faire tourner plusieurs threads en même temps alors que votre ordinateur ne possède qu'un seul microprocesseur ? La réponse vient de manière assez évidente : A tout moment, il n'y a en fait qu'un seul thread en cours d'exécution, et éventuellement d'autres threads en attente d'exécution.
Si le système permet de partager le temps d'exécution entre les différents threads, il leur donne chacun leur tour un petit temps d'exécution du processeur (quelques millisecondes). Sinon, chaque fois qu'un thread a terminé d'exécuter une série d'instructions et qu'il cède le contrôle au système, le système exécute un des threads en attente, et ainsi de suite... Si la série d'instructions qu'exécute chaque thread prend un temps assez court, l'utilisateur aura l'illusion que tous les threads fonctionnent ensemble.
Le seul contrôle que peut avoir le programmeur sur la gestion de l'ordre dans lequel les threads en attente s'exécuteront, s'effectue en donnant une priorité à chaque thread qu'il crée. Quand le système doit déterminer quel thread en attente doit être exécuté, il choisit celui avec la priorité la plus grande, ou à priorité égale, celui en tête de file d'attente.

!

Sur certains systèmes, la Machine Virtuelle Java ne partage pas d'elle-même le temps du processeur entre les threads susceptibles d'être exécutés. Si vous voulez que vos programmes Java se comportent similairement sur tous les systèmes, vous devez céder le contrôle régulièrement dans vos threads avec les méthodes telles que sleep () ou yield (), pour permettre aux autres threads en attente, de s'exécuter. Sinon, tant que l'exécution d'un thread n'est pas interrompue, les autres threads resteront en attente !

La création d'un thread

Il existe deux moyens d'écrire des threads dans un programme : Les deux moyens passent par l'écriture d'une méthode run () décrivant les instructions que doit exécuter un thread. Cette méthode run () est soit déclarée dans une classe dérivée de la classe Thread , soit déclarée dans n'importe quelle classe qui doit alors implémenter l'interface Runnable (cette interface ne décrit que la méthode run ()). La seconde méthode est très utile : elle permet d'ajouter les fonctionnalités des threads à une classe existante, dans une classe dérivée.
Par exemple, elle est utilisée par la classe TimeCounter qui dérive de la classe Counter et implémente l'interface Runnable. La classe Counter a d'abord été créée pour des besoins simples : Avoir à disposition un compteur digital au look sympa, avec des méthodes telles que incrementCounter () ou decrementCounter (). Puis, le besoin s'est fait sentir d'avoir un compteur de temps : il a suffi donc de créer une classe TimeCounter dérivée de Counter, et d'y ajouter (entre autres) la méthode run (), qui incrémente toutes les secondes le compteur.
Une autre démarche aurait pu être de créer la classe TimeCounter en la dérivant de la classe Thread, et d'y ajouter en utilisant la composition un champ de classe Counter, et une méthode run () effectuant les mêmes opérations. Mais, en conception orientée objet, cette seconde démarche semblait moins naturelle : En effet, un objet TimeCounter est plutôt comme tout objet Counter, un objet graphique auquel il a été ajouté la possibilité de s'incrémenter automatiquement toutes les secondes.

Un certain nombre de méthodes sont nécessaires pour contrôler l'exécution d'un thread. Elles sont toutes décrites au paragraphe décrivant la classe Thread, mais en voici les principales :

Pour illustrer l'utilisation des threads, voici un exemple d'un chronomètre affichant les 1/10 de seconde (Utiliser le bouton Arrêter pour l'arrêter et la redémarrer) :

Applet Chrono Applet PlayApplet

et le programme Java correspondant (à copier dans un fichier dénommé Chrono.java et invoqué à partir d'un fichier HTML) :

import java.awt.*;
import java.applet.Applet;
 
public class Chrono extends Applet implements Runnable
{  
  private Thread chronometre;
  private int    dixiemeseconde = 0;
  
  // Méthode appelée par le système au démarrage de l'applet
  public void start ()
  {
    // Au début de l'applet, création et démarrage du chronomètre
    chronometre = new Thread (this);
    chronometre.start ();
  }
 
  public void run ()
  {
    try
    {
      while (chronometre.isAlive ())
      {
        // Dessine le compteur (appel indirect à la méthode paint ()), 
        // puis l'augmente de 1
        repaint ();
        dixiemeseconde++;
        // Arrête le thread pendant 1/10 s (100 ms)
        Thread.sleep (100);
      }
    }
    catch (InterruptedException e) { }
  }
 
  // Méthode appelée par le système à l'arrêt de l'applet
  public void stop ()
  {
    // A la fin de l'applet, arrêt du chronometre
    chronometre.stop ();
  }
 
  // Méthode appelée par le système pour mettre à jour le dessin de l'applet
  public void paint (Graphics gc)
  {
    // Dessine le temps écoulé sous forme de hh:mm:ss:d en noir et helvetica
    gc.setColor (Color.black);
    gc.setFont  (new Font ("Helvetica", Font.BOLD, size ().height));
    gc.drawString (dixiemeseconde / 36000
                   + ":" + (dixiemeseconde / 6000) % 6 + (dixiemeseconde / 600) % 10
                   + ":" + (dixiemeseconde / 100) % 6  + (dixiemeseconde / 10) % 10
                   + ":" + dixiemeseconde % 10,
                   2, size ().height - 2);
  }
}

Ce programme s'utilisant sous forme d'applet, la classe Chrono dérive de Applet, et implémente l'interface Runnable. Comme décrit au chapitre sur les applets et aux chapitres suivants, la méthode paint () de la classe Applet est appelée pour mettre à jour le dessin apparaissant dans la fenêtre d'une applet : Ici, elle est outrepassée pour dessiner le chronomètre.
Quand l'applet est créée, une instance de la classe Chrono est allouée et la méthode start () créant le thread chronometre, est appelée. Si vous observez bien le comportement de cette applet, vous vous rendrez facilement compte que le chronomètre à une tendance à retarder... Ceci est normal : En effet, à chaque tour de boucle while (), le thread est arrêté pendant un dixième de seconde grâce à l'appel Thread.sleep (100), après le redessin de l'applet avec la méthode repaint () dans run (). Mais, le fait de redessiner le chronomètre prend un faible délai qui s'additionne au 1/10 de seconde d'arrêt du thread chronometre. Une programmation plus précise devrait notamment tenir compte de ce délai pour le soustraire de la valeur de 100 millisecondes passée à la méthode sleep (). La classe System déclare une méthode currentTimeMillis (), donnant le temps courant, qui peut vous y aider. A vous de jouer !...

Les états d'un thread

Pendant son existence, un thread passe par plusieurs états qu'il est utile de connaître pour bien comprendre les threads et leurs possibilités. La figure suivante représente l'ensemble des états possibles d'un thread, et les transitions existantes pour passer d'un état dans l'autre. Ne vous inquiétez pas par sa complexité, vous aurez besoin essentiellement des méthodes décrites dans le paragraphe précédent (start (), stop (), yield () et sleep ()).

Etats d'un thread
figure 10. Etats d'un thread

Quand un nouveau thread est créé, il est dans l'état nouveau thread et ne devient exécutable qu'après avoir appelé la méthode start () sur ce nouveau thread.

Parmi tous les threads dans l'état exécutable, le système donne le contrôle au thread de plus grande priorité, ou à priorité égale, celui en tête de file d'attente, parmi les threads dans l'état exécutable. Le thread qui a le contrôle à un moment donné est le thread courant. Le thread courant en cours d'exécution cède le contrôle à un autre thread exécutable dans l'une des circonstances suivantes :

Les deux derniers méthodes ne sont pas static et peuvent être invoquées aussi sur les threads exécutables qui ne sont en cours d'exécution.

La synchronisation des threads

Tous les threads d'une même Machine Virtuelle partage le même espace mémoire, et peuvent donc avoir accès à n'importe quels méthode ou champ d'objets existants. Ceci est très pratique, mais dans certains cas, vous pouvez avoir besoin d'éviter que deux threads n'aient accès n'importe quand à certaines données. Si par exemple, un thread threadCalcul a pour charge de modifier un champ var1 qu'un autre thread threadAffichage a besoin de lire pour l'afficher, il semble logique que tant que threadCalcul n'a pas terminé la mise à jour ou le calcul de var1, threadAffichage soit interdit d'y avoir accès. Vous aurez donc besoin de synchroniser vos threads.

Utilisation de synchronized

La synchronisation des threads se fait grâce au mot clé synchronized, employé principalement comme modificateur d'une méthode. Soient une ou plusieurs méthodes methodeI () déclarées synchronized, dans une classe Classe1 et un objet objet1 de classe Classe1 : Comme tout objet Java comporte un verrou (lock en anglais) permettant d'empêcher que deux threads différents n'aient un accès simultané à un même objet, quand l'une des méthodes methodeI () synchronized est invoquée sur objet1, deux cas se présentent :

Si une méthode synchronized d'une classe Classe1 est aussi static, alors à l'appel de cette méthode, le même mécanisme s'exécute mais cette fois-ci en utilisant le verrou associé à la classe Classe1.
Si Classe1 a d'autres méthodes qui ne sont pas synchronized, celles-ci peuvent toujours être appelées n'importe quand, que objet1 soit verrouillé ou non.

Voici un exemple illustrant l'utilisation de méthodes synchronized, avec une applet affichant les résultats d'un calcul de courbes, quand ceux-ci sont valables. Comme cette applet fait des calculs continuels dans des boucles sans fin, elle n'est pas incluse dans cette page pour éviter de bloquer votre navigateur, mais essayez-là sur votre machine pour découvrir tout l'intérêt de la synchronisation des threads.

Applet AfficheurDeCalcul

Voici le programme Java (à copier dans un fichier dénommé AfficheurDeCalcul.java et invoqué à partir d'un fichier HTML) :

import java.applet.Applet;
import java.awt.*;
 
public class AfficheurDeCalcul extends Applet
{
  private Thread calculateur;
  private Thread afficheur;
  
  // Méthode appelée par le système au démarrage de l'applet
  public void start ()
  {
    setBackground (Color.white);
    // Démarrage de deux threads l'un pour calculer une courbe, 
    // l'autre pour l'affichage
    calculateur = new Calculateur (this);
    afficheur   = new Afficheur   (this);
    calculateur.start ();
    afficheur.start ();
  }
 
  // Méthode appelée par le système à l'arrêt de l'applet
  public void stop ()
  {
    // Arrêt des deux threads 
    afficheur.stop ();
    calculateur.stop ();
  }
 
  private int [ ] courbe;
 
  // calculerCourbe () et paint () sont 
  // synchronized ce qui les empêche de fonctionner simultanément
  synchronized public void calculerCourbe ()
  {
    // Création d'un tableau de la largeur de l'applet
    courbe  = new int [size ().width];
    // Calcul des points d'une sinusoïde avec fréquence aléatoire
    double pasCalcul = 2 * Math.PI / courbe.length / Math.random ();
    for (int i = 0; i < courbe.length; i++)
      courbe [i] = (int)(  (Math.sin (i * pasCalcul) + 1) 
                         * size ().height / 2);
  }
 
  synchronized public void dessinerCourbe ()
  {
    update (getGraphics ()); // update () efface le fond puis appelle paint ()
  }
 
  // Méthode appelée par le système pour mettre à jour le dessin de l'applet
  synchronized public void paint (Graphics gc)
  {
    if (courbe != null)
    {
      // Dessin de la courbe en noir en reliant les points un à un
      gc.setColor (Color.black);
      for (int i = 1; i < courbe.length; i++)	  
        gc.drawLine (i - 1, courbe [i - 1], i, courbe [i]);
    }
  }
}
 
class Calculateur extends Thread
{
  private AfficheurDeCalcul applet;
  
  public Calculateur (AfficheurDeCalcul applet)
  {
    this.applet = applet;
  }
 
  public void run ()
  {
    while (isAlive ())
      applet.calculerCourbe (); // Lance les calculs indéfiniment
  }
}
 
class Afficheur extends Thread
{
  private AfficheurDeCalcul applet;
  
  public Afficheur (AfficheurDeCalcul applet)
  {
    this.applet = applet;
  }
 
  public void run ()
  {
    while (isAlive ())
      applet.dessinerCourbe (); // Lance les affichages indéfiniment
  }
}

Dans cette exemple, les méthodes calculerCourbe () et dessinerCourbe () de la classe AfficheurDeCalcul sont synchronized. Quand calculerCourbe () préparent les résultats dans le tableau courbe de l'applet, il ne faut pas qu'un autre thread puisse dessiner la courbe de cette applet en appelant dessinerCourbe (), et inversement !
L'objet représentant l'applet est verrouillé à l'appel de ces méthodes, pour bloquer tout autre thread tentant d'invoquer calculerCourbe () ou dessinerCourbe () sur cet objet. Les deux threads calculateur et afficheur s'interdisent ainsi mutuellement d'exécuter simultanément calculerCourbe () ou dessinerCourbe () sur l'objet calculateur. Si, en recopiant l'exemple, vous essayez de supprimer l'un ou les deux synchronized, vous verrez tout à coup que les courbes affichées ne sont plus très régulières, preuve que la courbe est modifiée pendant son affichage !...
A l'usage, vous vous rendrez compte que les boucles sans fin (ou presque !) des méthodes run () fonctionnent généralement correctement mais ont une forte tendance à plomber les performances du système, car elles tournent continuellement sans s'arrêter... Le programme se présente ainsi par soucis de simplification et pour que vous puissiez vous rendre compte que deux threads qui s'ignorent (ils ne s'appellent jamais l'un l'autre) peuvent se synchroniser pour accéder à un même objet pour obtenir un résultat correct.

Le système ne crée pas de file d'attente pour les threads bloqués : Quand un objet est déverrouillé, n'importe quel thread bloqué sur cet objet est susceptible d'être débloqué pour avoir accès à une de ses méthodes synchronized. Dans l'exemple précédent, rien n'empêche en effet les méthodes calculerCourbe () ou dessinerCourbe () de s'exécuter plusieurs fois de suite, avant que l'autre méthode ne verrouille l'objet représentant l'applet et puisse s'exécuter. Pour vous le prouver, il vous suffit d'ajouter des appels à System.out.println (...) dans ces deux méthodes...

Il existe une autre syntaxe d'utilisation de synchronized :

class Classe1
{
  // ...
  void methode1 ()
  {
    // ...
    synchronized (objet1)
    {
      // objet1 est verrouillé
      // jusqu'à la fin du bloc
    }
  }
}

Un thread peut accéder à un bloc synchronized, si objet1 n'est pas verrouillé par un autre thread. Si c'est le cas, comme pour une méthode synchronized, le thread est bloqué tant que objet1 n'est pas déverrouillé.

!

La Machine Virtuelle Java n'a pas de moyen de repérer les deadlocks (impasses) : Ceux-ci peuvent survenir quand par exemple, deux threads thread1 et thread2 restent dans l'état bloqué parce que thread1 attend qu'un objet objetX soit déverrouillé par thread2, alors que thread2 attend qu'un objetY soit déverrouillé par thread1. C'est à vous de faire attention dans votre programmation pour qu'un deadlock ne survienne pas.

Synchronisation avec wait () et notify ()

Comme il est expliqué dans l'exemple précédent, synchronized permet d'éviter que plusieurs threads aient accès en même temps à même objet, mais ne garantit pas l'ordre dans lequel ces méthodes seront exécutées par des threads. Pour cela, il existe plusieurs méthodes de la classe Object qui permettent de mettre en attente volontairement un thread sur un objet (avec les méthodes wait ()), et de prévenir des threads en attente sur un objet que celui-ci est à jour (avec les méthodes notify () ou notifyAll ()).
Ces méthodes ne peuvent être invoquées que sur un objet verrouillé par le thread courant, c'est-à-dire que le thread courant est en train d'exécuter une méthode ou un bloc synchronized, qui a verrouillé cet objet. Si ce n'est pas le cas, une exception IllegalMonitorStateException est déclenchée.

Quand wait () est invoquée sur un objet objet1 (objet1 peut être this), le thread courant perd le contrôle, est mis en attente et l'ensemble des verrous d'objet1 est retiré. Comme chaque objet Java mémorise l'ensemble des threads mis en attente sur lui, le thread courant est ajouté à la liste des threads en attente de objet1. objet1 étant déverrouillé, un des threads bloqués parmi ceux qui désiraient verrouiller objet1, peut passer dans l'état exécutable et exécuter une méthode ou un bloc synchronized sur objet1.

Un thread thread1 mis en attente est retiré de la liste d'attente de objet1, quand une des trois raisons suivantes survient :

thread1 est mis alors dans l'état exécutable, et essaye de verrouiller objet1, pour continuer son exécution. Quand il devient le thread courant, l'ensemble des verrous qui avait été enlevé d'objet1 à l'appel de wait (), est remis sur objet1, pour que thread1 et objet1 se retrouvent dans le même état qu'avant l'invocation de wait ().

!

Un thread mis en attente en utilisant la méthode wait () sans argument sur un objet, ne peut redevenir exécutable qu'une fois qu'un autre thread a invoqué notify () ou notifyAll () sur ce même objet. Donc, wait () doit toujours être utilisé avec notify (), et être invoqué avant cette dernière méthode.


Par exemple, si dans l'exemple précédent, vous ajoutez à la fin de la méthode calculerCourbe (), vous ajoutez notifyAll () et au début de dessinerCourbe (), vous ajoutez wait (), vous obtiendrez ceci :

public class AfficheurDeCalcul extends Applet
{
  // ...
 
  synchronized public void calculerCourbe () 
  {
    courbe = new int [size ().width];
    double pasCalcul = 2 * Math.PI / courbe.length / Math.random ();
    for (int i = 0; i < courbe.length; i++)
      courbe [i] = (int)(  (Math.sin (i * pasCalcul) + 1) 
                         * size ().height / 2);
 
    // Prévenir les autres threads du calcul d'une nouvelle courbe
    notifyAll ();
  }
 
  synchronized public void dessinerCourbe ()
  {
    try
    {
      // Attendre qu'une nouvelle courbe soit calculée
      wait ();
      update (getGraphics ());
    }
    catch (InterruptedException e) { }
  }
 
  // ...
}

A l'appel de wait () (ici sur l'objet this), le thread afficheur qui appelle la méthode dessinerCourbe () est mis en attente jusqu'à ce que ce que calculerCourbe () appelle notifyAll () pour prévenir les threads en attente qu'une nouvelle courbe est maintenant disponible. Ceci évite que dessinerCourbe () soit éventuellement exécutée plusieurs fois de suite alors qu'aucune nouvelle courbe n'a été calculée.
Il vaut mieux utiliser notifyAll () que notify (), car il est possible d'enrichir ce programme en créant par exemple des threads qui devront appeler dessinerCourbe () pour mettre à jour des fenêtres supplémentaires, ou en créant un autre thread appelant une méthode synchronized qui enregistre la courbe dans un fichier. Si la méthode notify () était appelée, un seul thread serait prévenu et mis à jour en ignorant les autres.

Cette modification du programme n'empêche toujours pas la méthode calculerCourbe () de s'exécuter plusieurs fois de suite, car le thread calculateur qui appelle cette méthode, prévient en invoquant notifyAll () les threads en attente qu'une nouvelle courbe a été calculée, mais n'est jamais mis en attente pour laisser les autres threads utiliser ces nouveaux résultats. Une dernière modification des méthodes calculerCourbe () et dessinerCourbe () permet au thread afficheur appelant dessinerCourbe () de prévenir le thread calculateur en attente qu'il a terminé de dessiner la nouvelle courbe :

public class AfficheurDeCalcul extends Applet
{
  // ...
 
  synchronized public void calculerCourbe () 
  {
    try
    {
      // Attendre que les autres threads aient utilisé une courbe
      if (courbe != null)
        wait ();
    }
    catch (InterruptedException e) { }
 
    courbe = new int [size ().width];
    double pasCalcul = 2 * Math.PI / courbe.length / Math.random ();
    for (int i = 0; i < courbe.length; i++)
      courbe [i] = (int)(  (Math.sin (i * pasCalcul) + 1) 
                         * size ().height / 2);
	                     
    notifyAll ();
  }
 
  synchronized public void dessinerCourbe ()
  {
    try
    {
      // Attendre qu'une courbe soit créée
      if (courbe == null)
        wait ();
      update (getGraphics ());
 
      // Prévenir que la courbe a été utilisée
      courbe = null;
      notify ();
    }
    catch (InterruptedException e) { }
  }
 
  // ...
}

Ici, en modifiant le champ courbe avec null ou un nouveau tableau, un thread peut savoir si l'autre à terminer son traitement ou non. Si ce traitement n'est pas terminé, le thread se met en attente. Il redeviendra exécutable quand l'autre thread le préviendra qu'il a fini en appelant notify ().
Vous noterez que dessinerCourbe () mettant à null le champ courbe avant d'appeler notify (), il faudrait utiliser une autre logique de programmation pour que cette courbe reste disponible pour d'autres threads qui seraient créés.

Cet exemple, utilisant deux boucles (sans fin) pour le calcul et l'affichage des courbes, entraîne une programmation d'un abord assez complexe. Mais, ceci n'est utilisé que pour des moyens de démonstration : Généralement, dans ce type de programme, un calcul est effectué ponctuellement sur commande et pas en boucle, et l'affichage attend la fin du calcul pour démarrer. Donc, la programmation avec uniquement synchronized comme dans la première version de cet exemple, suffira dans la plupart des cas pour synchroniser l'accès aux données.

!

La programmation de la synchronisation des threads est une tâche ardue, sur laquelle vous passerez sûrement du temps... Si vous désirez l'utiliser, il faut bien s'imaginer par quels états vont passer les threads, quelle implication aura l'utilisation des méthodes wait () et notify () sur l'ordre d'exécution des instructions du programme, tout en gardant bien à l'esprit que ces méthodes ne peuvent être invoquées que sur des objets verrouillés.
Le piège le plus classique est de se retrouver avec un deadlock parce que les threads sont tous en attente après avoir appelé chacun d'eux la méthode wait ().

La classe java.lang.Thread

Champs

public final static int MIN_PRIORITY
public final static int NORM_PRIORITY
public final static int MAX_PRIORITY

Ces constantes sont utilisées en argument de la méthode setPriority (), pour donner une priorité à vos threads (MIN_PRIORITY est égal à 1, NORM_PRIORITY à 5 et MAX_PRIORITY à 10). NORM_PRIORITY est la priorité par défaut d'un thread.

Constructeurs

public Thread ()
 
public Thread (Runnable target)

Construit un nouveau thread à partir de la classe target implémentant l'interface Runnable. target doit implémenter la méthode run () qui sera la méthode exécutée au démarrage du nouveau thread créé.

public Thread (ThreadGroup group, Runnable target)
                   throws SecurityException, IllegalThreadStateException

Construit un nouveau thread à partir de la classe target avec comme groupe de thread group. La classe ThreadGroup permet de regrouper un ensemble de threads, et d'exécuter (stop (), suspend (),...) des méthodes sur tous les threads d'un groupe.

public Thread (String name)
public Thread (ThreadGroup group, String name)
                   throws SecurityException, IllegalThreadStateException
public Thread (Runnable target, String name)
public Thread (ThreadGroup group, Runnable target, String name)
                   throws SecurityException, IllegalThreadStateException

Mêmes constructeurs que précédemment avec un nom name.

Méthodes

La classe Thread compte un grand nombre de méthodes, dont voici la description des plus intéressantes. Pour pouvoir manipuler le thread courant que vous ne connaissez pas forcément, certaines de ces méthodes sont des méthodes de classe :

public static Thread currentThread ()

Renvoie une référence sur le thread actuellement en cours d'exécution.

public synchronized void start () throws IllegalThreadStateException

Provoque le démarrage du thread sur lequel start () est invoqué puis l'appel à la méthode run (). Cette méthode rend la main immédiatement (le nouveau thread est lancé en parallèle au thread courant).

public void run ()

run () est la méthode où sont décrites les instructions que doit exécuter un thread. Elle est appelée une fois que le thread a démarré. run () doit être outrepassée dans une classe dérivée de Thread ou une classe implémentant l'interface Runnable.

public final synchronized void stop () throws SecurityException

Arrête le thread sur lequel stop () est invoqué.

public final void stop (Throwable exception)
                          throws SecurityException

Arrête le thread sur lequel stop () est invoqué en déclenchant l'exception exception.

public final boolean isAlive ()

Renvoie true si un thread est vivant, c'est-à-dire que ce thread a démarré avec start () et n'a pas été arrêté soit avec stop (), soit parce qu'il a terminé d'exécuter toutes les instructions de la méthode run ().

public static void yield ()

Permet de suspendre le thread courant pour laisser la main à d'autres threads en attente d'exécution.

public static void sleep (long millis) throws InterruptedException
public static void sleep (long millis,
                           int nanos) throws InterruptedException

Provoque l'arrêt du thread courant pendant millis millisecondes, ou pendant millis millisecondes et nanos nanosecondes. Ces méthodes sont susceptibles de déclencher une exception InterruptedException, qui n'est pas utilisée dans Java 1.0, mais vous oblige quand même à inclure l'appel à sleep () dans un try ... catch.

public final void suspend () throws SecurityException

Suspend l'exécution d'un thread vivant. Si plusieurs suspend () ont été invoquées sur un même thread, un seul resume () est nécessaire pour que ce thread reprenne son activité.

public final void resume () throws SecurityException

Reprend l'exécution d'un thread, après une suspension avec suspend (). Si ce thread n'a pas été suspendu, le thread poursuit son exécution.

public void checkAccess ()

Vérifie si le thread courant peut modifier le thread sur lequel checkAccess () est invoqué. Si cela lui est interdit, une exception SecurityException est déclenchée.

public final void setPriority (int newPriority)
                             throws SecurityException, IllegalArgumentException
public final int getPriority ()

Modifie ou renvoie la priorité d'un thread. newPriority doit avoir une valeur comprise entre MIN_PRIORITY et MAX_PRIORITY.

public final void setName (String name) throws SecurityException
public final String getName ()

Modifie ou renvoie le nom d'un thread.

public final void setDaemon (boolean on)
                        throws SecurityException, IllegalThreadStateException
public final boolean isDaemon ()

Permet de spécifier ou de savoir si un thread est un thread qui tourne en tâche de fond, pour rendre en général des services aux autres threads (daemon thread en anglais). Quand il n'a plus que des threads qui tournent en tâche de fond dans le système, la Machine Virtuelle Java s'arrête.

public final synchronized void join (long millis) throws InterruptedException
public final synchronized void join (long millis, int nanos)
                           throws InterruptedException
public final void join () throws InterruptedException

Ces méthodes provoquent l'arrêt du thread courant jusqu'à la mort du thread sur lequel est invoqué join (), et pendant un délai maximum de de millis millisecondes, ou millis millisecondes et nanos nanosecondes.

public static void dumpStack ()

Imprime sur System.err l'état de la pile d'exécution du thread courant.

public final ThreadGroup getThreadGroup ()

Renvoie le groupe de threads auquel appartient un thread.

public static int activeCount ()
public static int enumerate (Thread tarray [ ])

Ces méthodes renvoient le nombre de threads actifs dans le groupe auquel appartient le thread courant, et la liste des threads actifs de ce groupe dans le tableau tarray ( tarray doit exister et être de taille supérieure ou égale à la valeur renvoyée par activeCount ()).

public void interrupt ()

Cette méthode et les deux suivantes ne sont implémentées qu'à partir de Java 1.1. Cette méthode permet d'interrompre un thread. Si ce thread est en attente, il est exécuté et une exception InterruptedException est déclenchée.

public static boolean interrupted ()
public boolean isInterrupted ()
 
public String toString ()

Renvoie une chaîne de caractère représentant un thread (comprenant son nom, sa priorité et le nom du groupe de thread auquel il appartient). Cette méthode outrepasse celle de la classe Object.

public void destroy ()
public int countStackFrames () throws IllegalThreadStateException

Exemples

Application PaperBoardServer.
Applets Chrono, AfficheurDeCalcul, ObservateurCalcul, PaperBoardClient, AnimationFleche, ScrollText et Horloge.


Page d'accueilFindIt !ContactLes exceptionsLes classes internesDébut de la page
© Copyrights 1997-2023 Emmanuel PUYBARET / eTeks
- Tous droits réservés -
Table des matièresHiérarchie des classes