Chap : Introduction à la programmation concurrente
en Java
Thread : séquence autonome d’exécution d’instructions au sein
d’un programme
Le multi-threading donne l’illusion de parallélisme de
l’exécution des bouts de programmes
Délivre un parallélisme réel sur une machine multiprocesseur
Pour créer des Threads…
Deux façons :
Façon 1 : Dériver une classe de la classe Thread.
Façon 2 : implémenter l’interface Runnable.
Un point commun : écrire une méthode run() qui fait
ce que doit faire le thread.
1ère façon
Etape 1 : Définir une classe fille de Thread et définition de la
méthode run()
public class MonThread extends Thread {
public void run() {
...
}
}
Etape 2 : Instancier un objet de la classe MonThread et lancer la
méthode prédéfinie start() prédéfinie
MonThread theThread = new MonThread ();
[Link]();
Rq : si on fait [Link]() alors run
s'exécute sans créer un nouveau thread
1ère façon
public class MonThread extends Thread {
public void run() {
for ( int i1=1; i1<100; i1++)
[Link](">>> i1 = "+i1);
}
}
class Test {
public static void main(String[] x) {
MonThread theThread = new MonThread ();
[Link]();
for ( int i2 =1; i2<100;i2++)
[Link](" i2 = "+i2);
}
1ère façon : une autre écriture
public class MonThread extends Thread {
MonThread {
[Link]() ;
}
public void run() {
for ( int i1=1; i1<100; i1++)
[Link](">>> i1 = "+i1);
}
}
new MonThread();
Façon 2
Etape_1 : définir une classe qui implémente l'interface Runnable, et
définition de la méthode run()
public class MonThread implements Runnable {
public void run() {
…
}
}
Etape_2 : créer un objet de cette classe
MonThread T = new MonThread( );
Etape_3 : créer un objet de la classe Thread prédéfinie de la façon
suivante :
Thread theThread = new Thread (T) ;
Etape_4 : Appeler la méthode start()
[Link]() ;
2ème façon (une autre écriture utilisant la classe
Runnable)
Runnable job = new Runnable() {
public void run() {
...
}
};
Thread t1 = new Thread(job, "Premier thread");
[Link]();
Thread t2 = new Thread(job, "Second thread");
[Link]();
Pourquoi on offre deux façons de définir les threads ?
Exercice : Écrire un programme qui créer cinq Threads
identiques
Mise en place de l'exclusion mutuelle
Deux mécanismes:
● Un mécanisme de synchronisation léger en utilisant le mot clé
volatile:
Int volatile x ;
si un thread_a change la valeur de x alors on a une garantie que toute
autre thread_b utilisant x trouvera la bonne valeur.
● Un mécanisme plus complet utilisant le mot clé synchronized.
● Sachant qu'a chaque objet Java est associé automatiquement un
(et un seul) verrou, appelé aussi moniteur de l'objet.
La directive synchronized
● On a le choix de faire l'exclusion mutuelle soit à une méthode en
totalité :
type_x synchronized methode_x () {…}
● Soit un bloc d'instructions :
i++ ; synchronized (this) {…} ; j++
ou
i++ ; synchronized (objet_a) {….} ; j++
C'est le verrou de l'objet courant qui est pris par le thread
courant.
Si un 2ème thread tente de prendre le verrou alors il se bloque.
La directive synchronized
Le verrou d'un objet O est libéré :
- soit à la fin du bloc synchronized() {...}
- soit à l'appel de la méthode [Link]() par le thread possédant le
verrou.
public class SavingsAccount
{
private float balance;
public synchronized void withdraw(float anAmount)
{
if ((anAmount>0.0) && (anAmount<=balance))
balance = balance anAmount;
}
public synchronized void deposit(float anAmount)
{
if (anAmount>0.0)
balance = balance + anAmount;
}
public class SavingsAccount
{
private float balance;
public void withdraw(float anAmount)
{
if (anAmount<0.0)
throw new IllegalArgumentException("Withdraw
amount negative");
synchronized(this)
{
if (anAmount<=balance)
balance = balance anAmount;
}
}
public void deposit(float anAmount)
{
La synchronisation coopérative avec les
méthodes wait() et notify()
● Wait() fait suspendre le thread courant jusqu'à ce que un autre
thread fait notify()
● Ceux sont des méthodes de la classe Object
● Ces méthodes doivent être appélées qu'à l'intérieur d”un bloc
synchronized {…}
wait()
● Trois syntaxes d'appels différentes:
wait(), [Link]() ou objet_x.wait()
● Dans les trois cas le thread appelant passe à l'état wait.
Mais pour des raisons différentes:
objet_x.wait(): Attente d'un signal de l' objet_x
[Link](): Attente d'un signal de l'objet courant
wait(): Attente d'un signal de cet objet thread (c.à d. du thread
courant)
● Le monitor de l'objet marque que ce thread appelant est en
attente d'un signal de cet objet.
wait()
● Le thread appelant objet_x.wait() doit être en
possession du verrou de objet_x:
synchronized (objet_x) {
…
objet_x.wait();
● Après l'appel à objet_x.wait() ce verrou est libéré ( afin
que le thread ne garde pas le verrou)
notify()
Trois syntaxes d'appels différentes:
notify(), [Link]() ou objet_x.notify()
● A l'appel de objet_x.notify() par un thread_b, le VJM
débloque l'un des threads en attente d'un signal de objet_x.
Mais le thread débloqué doit récupérer le verrou avant de
progresser
● objet_x.notifyAll() débloquent tous les thread_b en
attente d'un signal de objet_x
Les états d'un thread Java
Attributs et méthodes de la classe
Thread
public class Thread implements Runnable {
public static final int MAX_PRIORITY, MIN
_PRIORITY, NORM _PRIORITY;
public Thread();
public Thread(String name);
…
public static Thread currentThread();
public static void sleep(long millis);
…
}
Attributs et méthodes de la classe
Thread
public class Thread implements Runnable {
...
public static void suspend();
public static void resume();
…
public static void start();
public static void stop();
public static void run();
public static void wait(); //arrête le
thread en attendant une notification
public static void notify(); // notification
des threads en attentes par wait
…
}
Le framework Executor ( à partir de Java 5)
Pb : si une application a à créer en tout et pour
tout M threads sachant qu'au maximum N
threads coexisteront au même temps, alors si
M>>N trop de temps serait perdu dans la création
des threads.
Solution : Utilisation d'un pool de threads
([Link]).
Le framework Executor (Java 5)
import [Link] ;
Runnable job = new Runnable() {
public void run() {
...
}
};
// Pool de 4 threads
ExecutorService pool = [Link](4);
[Link](job);
[Link](job);
Voir Demo...