21 novembre 2008
Séance 1

Les threads
https://tetras.u-strasbg.fr/prive/pedagogie/LP/P51/index.php?menu=101

====== Cours ======

Le but de ce cours est d'utiliser la puissance des nouveaux processeurs pour faire des applications rapides.

threads = sous partie d'un processus, donc se lance plus vite qu'un processus et prend moins d'espace mémoire
Faire un thread implique une nouvelle pile d'exécution et de nouveaux registres alloués.

===== Les Threads, dans Java =====

Dans la classe Java.lang.Thread, il faut l'interface *Runnable :*, et la méthode *run()* (qui ne prend pas d'arguments).

Faire un thread en Java : 
  * soit on étend (sous - classer) un thread (à l'aide d'extends)
  * soit on implémente *Runnable* à notre classe Java.

===== Comment choisir quelle méthode utiliser ? =====

Comme Java n'accepte pas l'héritage multiple, mieux vaut implémenter qu'étendre si on a déjà étendu notre classe Java avec une autre.

Implémenter "marche à tout les coups", contrairement à l'autre méthode.

===== Gestion des priorités =====

Si un thread n'est pas actif, il ne consommera pas de temps CPU, vu qu'il est mis de côté.

MAX_PRIORITY et MIN_PRIORITY sont des variables définies dans la classe Thread.

===== Concurrence d'accès =====

Pour éviter l'interblocage, on utilise le mot clé *synchronized* pour gérer les concurrences d'accès.

==== Concurrence d'accès sur une méthode ====

Le <u>verrou est sur l'instance de la classe</u> et pas sur la classe elle même

Mettre un verrou pour une instance d'un champ statique (static) n'est pas la bonne solution !!!

==== Contrôler l'accès à un objet ====

Utile si la classe a été créée sans être prévue/pensée pour les Threads.

Ceci permet d'utiliser une classe dans des Threads.

===== Groupes de Threads =====

Seulement si on a beaucoup de threads (en faisant des *ThreadGroup*).

Permet de lancer un ensemble de threads sans avoir à les instancier l'un après l'autre.

====== Exercice ======

===== Démonstration du cas de l'executor =====

3 producteurs ont une liste de produits. Ils gèrent une file d'attente.

Les consommateurs 1 et 2 tentent d'accéder à la file d'attente.

Il faut gérer les processus inactifs et la synchronisation.

* * *

<code java>
Executor ex = | Executors.new SingleThread();
                        | Executors.new ThreadPool(2);

for (int i=0 ; i < 1 000 ; i++)
    ex.execute(new Runnable() {
        public void run() {
            System.out.println("o")
        }
    });

</code>

Dans les exécuteurs il n'y a pas de gestion de dépendances, donc on ne sait pas si le 5ième envoyé sera exécuté après le 4ième : ça faut le faire à la main.

===== Cas d'interblocage =====

Tout objet

<code java>
class DeadLock {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    void a() throws Interrupted Exception {
        lock1.wait();
        lock2.notify();
    }

    void b() throws Interrupted Exception {
        lock2.wait();
        lock1.notify();
    }
}
</code>

Un thread appelle la méthode a() : 
  * Le lock1 passe en attente.

Un second thread appelle la méthode b() :
  * Il se met en attente d'un notify (comme le lock1)

Donc cela fait un verrou mortel, car on en sort pas. Pourquoi : 
  * lock1 attend lock1.notify (qui est dans lock2)
  * lock2 attend lock2.notify (qui est dans lock1, lui même en attente d'un notify)

Nous sommes donc dans un DeadLock.

===== Explications =====

wait() : suspend un thread courant
notify(): réactive UN thread qui a fait un *wait()* sur l'instance
notifyAll(): réactiver TOUS les threads qui ont fait un *wait()* sur l'instance

Quand un producteur aura fini de produire, il va activer UN thread pour le consommateur : pour pas mettre sur la paille le second consommateur.

==== Arrêt d'un thread ====

<code java>
T1
Object t2 ;
t2.wait() ;
</code>

Dans ce cas, T1 s'arrête.

<code java>
T1
Thread t2;
t2.wait() ;
</code>
Ici c'est T2 qui s'arrête.


