US

Interaction entre threads

Maintenant qu'on a vu comment arrêter proprement un thread, on va s'intéresser à un autre problème de contrôle, à savoir cela de gérer l'interaction entre threads. Pour ce faire, il existe un mécanisme dans Java qu'on va étudier dans cette section. Ce mécanisme est à la base des nombreuses formes d'interaction courantes en programmation concurrente et il est donc très intéressant de bien le comprendre.

Tout ce qu'on va voir ici se base sur des méthodes de la classe Object :

public final void wait() throws InterruptedException;
public final void notify();
public final void notifyAll();

Pour qu'un thread puisse appeler une de ces méthodes sur un objet, il faut que le thread possède le lock de l'objet. L'appel doit donc se faire dans un bloc synchronized sur l'objet, comme on l'a vu au chapitre 2. Sinon, une exception de type IllegalMonitorStateException sera levée (exception hors-contrôle).

Endormir un thread

Tous les objets possèdent, outre un lock, un ensemble de threads en attente. Pour un objet o, lorsqu'on exécute la méthode o.wait(), le thread qui fait l'appel passe dans l'état Waiting. De plus, le lock de o que le thread possédait est libéré.

Voyons cela sur l'exemple suivant. La première chose qui est faite est d'obtenir le lock de l'objet courant. Ensuite, on appelle la méthode wait sur ce même objet. À ce moment, le thread qui exécute cette tâche est endormi (passe dans l'état Waiting) et ajouté à la liste d'attente de l'objet courant. Tant qu'il n'est pas réveillé, il ne sera donc plus exécuté sur la machine. De plus, une fois ajouté à la liste d'attente, sachez que le thread libère le lock qu'il possédait.

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
public class SleepingTask implements Runnable
{
    public void run()
    {
        try
        {
            synchronized (this)
            {
                System.out.println ("Go for sleeping");
 
                this.wait();
            }
 
            System.out.println ("Normal End");
        }
        catch (InterruptedException exception)
        {
            System.out.println ("Interrupted End");
        }
    }
}
Listing 3.7 Thread mis en attente.

Voyons un exemple d'utilisation de cette classe. On va créer un nouveau thread qui exécute la tâche représentée par la classe SleepingTask. Ce programme ne se terminera pas. En effet, bien que le thread principal se termine, le thread exécutant SleepingTask est toujours vivant, ce qui empêche le programme de se terminer.

1 
2 
3 
4 
5 
6 
7 
8 
public static void main (String[] args)
{
    SleepingTask task = new SleepingTask();
    Thread thread = new Thread (task);
    thread.start();
 
    System.out.println ("Main thread ended");
}
Listing 3.8 Un programme qui ne se termine pas à cause d'un thread en attente.

La figure suivante montre la situation finale, lorsque le programme est bloqué. On voit bien qu'il reste un thread actif, mais qui est endormi. Aucun autre thread n'est disponible pour le réveiller et le programme restera donc bloqué indéfiniment.

État du programme bloqué du listing 3.8
Figure 3.1 État du programme bloqué du listing 3.8.

Réveiller un thread

Pour réveiller un thread qui est en endormi et dans la file d'attente d'un objet o, il suffit d'exécuter la méthode o.notify(). Le thread qui appelle cette méthode doit avant tout posséder le lock sur l'objet. Une fois cette méthode appelée, un des threads de la file d'attente va se faire réveiller. Néanmoins, ce dernier ne pourra pas se remettre à s'exécuter directement, il devra avant tout ré-obtenir le lock. En effet, l'appel wait est fait dans un bloc synchronized et il faut donc le lock pour pouvoir en sortir.

Voyons maintenant comme débloquer le programme précédent, en ajoutant une instruction de réveil dans le thread principal.

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
public static void main (String[] args)
{
    SleepingTask task = new SleepingTask();
    Thread thread = new Thread (task);
    thread.start();
 
    try
    {
        Thread.sleep (5000);
    }
    catch (InterruptedException exception){}
 
    synchronized (task)
    {
        task.notify();
    }
    System.out.println ("Main thread ended");
}
Listing 3.9 Réveiller un thread endormi.

Une fois le thread exécutant SleepingTask démarré, on met le thread principal en attente pendant cinq secondes. Ensuite, on appelle la méthode task.notify() afin de réveiller un thread se trouvant dans la file de cet objet. Ceci va débloquer le programme et on pourra voir sur la sortie standard :

Go for sleeping
Main thread ended
Normal End

Notez que l'ordre d'apparition des lignes pourrait être différent. Les deux dernières lignes pourraient être inversées. Vous voyez pourquoi ?

Réveiller tous les threads

La méthode notify permet donc de réveiller un des threads qui est en attente. On peut également décider de réveiller tous les threads qui sont en attente en utilisant la méthode notifyAll.

  • Espace membre
  • Learning Center
  • Les forums
  • Livre d'or
  • Imprimer
  • Boutique
  • Info
  • Règlement
  • Erreur
  • Newsletter

MyPagerank.Net

Firefox 3.6

Browse Happy logo

Open Clip Art Library

Join our Facebook Group

Twitter

Copyright © 2000-2012 UKO. Toute reproduction strictement interdite sans autorisation du webmaster

Valid XHTML 1.1 !
Valid CSS2 !
Level Triple-A conformance icon, W3C-WAI Web Content Accessibility Guidelines 1.0
ICRA Internet Content Rating Association
Creative Commons License
Site optimisé pour Firefox avec une résolution 1024x768 --- Page chargée en 0.0698111 secondes --- This site uses Thumbshots previews