SlideShare une entreprise Scribd logo
1  sur  32
Télécharger pour lire hors ligne
Concurrence
rendez vous
Rémi Forax
Echange d'information
Si deux threads veulent s'échanger des
données
– Les données vont transitées par le tas (dans des
champs)
– Il faudra une ou plusieurs sections critiques pour
éviter les états incohérents
mais ce n'est pas suffisant, il faut aussi que la
thread qui veut recevoir des données soit mis
en attente
Exemple
Qu'affiche ce code ?
public class Holder {
private int value;
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
holder.value = 12;
}).start();
System.out.println(holder.value);
}
}
Exemple (suite)
Trouver les 2 bugs !
public class Holder {
private int value;
private boolean done;
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
holder.value = 12;
holder.done = true;
}).start();
while(!holder.done) {
// ne rien faire !
}
System.out.println(holder.value);
}
}
Exemple (suite/2)
Bug 1: attente active, le CPU tourne en boucle
public class Holder {
private int value;
private boolean done;
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
holder.value = 12;
holder.done = true;
}).start();
while(!holder.done) {
// ne rien faire !
}
System.out.println(holder.value);
}
}
On réchauffe la planète
Exemple (suite/2)
Bug 1: attente active, le CPU tourne en boucle
public class Holder {
private int value;
private boolean done;
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
holder.value = 12;
holder.done = true;
}).start();
while(!holder.done) {
// ne rien faire !
}
System.out.println(holder.value);
}
}
On réchauffe la planète
Exemple (suite/3)
Bug 2: Le JIT peut introduire un registre
pour la valeur holder.done
public class Holder {
private int value;
private boolean done;
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
holder.value = 12;
holder.done = true;
}).start();
boolean r0 = holder.done;
while(!r0) {
// ne rien faire !
}
System.out.println(holder.value);
}
}
Oups
Exemple (suite/4)
Bug 2 bis: Le JIT ou le CPU peut ré-organiser les deux
assignations
public class Holder {
private int value;
private boolean done;
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
holder.done = true; // holder.value = 12;
holder.value = 12; // holder.done = true;
}).start();
while(!holder.done) {
// ne rien faire !
}
System.out.println(holder.value);
}
}
Oups
Exemple (suite/5)
Un section critique résoud le bug 2
public class Holder {
private int value;
private boolean done;
private final Object lock = new Object();
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
synchronized(holder.lock) {
holder.value = 12;
holder.done = true;
}
}).start();
for(;;) {
synchronized(holder.lock) {
if (holder.done) {
break;
}
}
}
synchronized(holder.lock) {
System.out.println(holder.value);
}
}
}
Attention il faut bien les 2 blocs synchronized
Et cela ne résoud pas le problème
de l'attente active !
Rendez vous
On veut une façon d'arrêter une thread tant qu'une
condition n'est pas vérifié
– La thread en attente doit être dé-schédulée
Lorque la condition est vrai, on veut réveillé la thread
– La thread en attente doit être re-scédulée
Ce mécanisme doit marcher avec les sections
critiques car sinon on a les problèmes de visibilité,
reorganisation, etc classique
Exemple de wait()/notify()
(mais pas objet)
public class Holder {
private int value;
private boolean done;
private final Object lock = new Object();
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(() -> {
synchronized(holder.lock) {
holder.value = 12;
holder.done = true;
holder.lock.notify();
}
}).start();
synchronized(holder.lock) {
while(!holder.done) {
holder.lock.wait();
}
System.out.println(holder.value);
}
}
}
Demande de mettre la thread
en attente
Reveil la thread si en attente
sinon ne fait rien
Exemple de wait()/notify()
(version objet !)
public class Holder {
private int value;
private boolean done;
private final Object lock = new Object();
private void init() {
synchronized(lock) {
value = 12;
done = true;
lock.notify();
}
}
private void display() {
synchronized(lock) {
while(!done) {
lock.wait();
}
System.out.println(holder.value);
}
}
●
public static void main(String[] args) {
Holder holder = new Holder();
new Thread(holder::init).start();
holder.display();
}
}
Demande de mettre la thread
en attente
Reveil la thread si en attente
sinon ne fait rien
wait()
object.wait()
– demande à arréter la thread courante
● Celle-ci est de-schedulé
– re-donne le moniteur associé à l'objet
une fois la thread “reveillé”
– re-prend le moniteur associé à l'objet
– demande à reprendre la thread
● La thread est re-schédulé
Conditions de reveil
Comment une thread peut être reveillé d'un
foo.wait() ?
– Si une autre thread appel foo.notify() ou
foo.notifyAll()
– Si une autre thread interrompt la thread courante
avec interrupt()
● dans ce cas foo.wait() lève InterruptedException
– Sans raison apparente (spurious wake-up)
notify() / notifyAll()
foo.notify()
– Demande le réveil d'une thread en attente sur foo
avec un foo.wait()
– Si aucune thread est en attente, le notify() est perdu
et il ne se passe rien
foo.notifyAll()
– Demande le réveil de toutes les thread en attente
sur foo avec un foo.wait()
Wait/notify et synchonized
foo.wait() ou foo.notify() ne peut être appelé que à
l'intérieur d'un bloc synchonized sur foo
– Pour wait(), c'est parce que wait() rend le moniteur
associé à l'objet après avoir endormi la thread courante
puis reprend le moniteur lorsque la thread est réveillé et
sort du wait()
– Pour notify(), c'est pour permettre à ce que la condition et
le notify() soit atomique du point de vue des autres
threads
Pourquoi un while sur une valeur ?
public class Holder {
private int value;
private boolean done;
private final Object lock = new Object();
private void init() {
synchronized(lock) {
value = 12;
done = true;
lock.notify();
}
}
private void display() {
synchronized(lock) {
while(!done) {
lock.wait();
}
System.out.println(holder.value);
}
}
public static void main(String[] args) {
...
}
}
Pourquoi il faut absolument
un while sur une valeur ?
Pourquoi pas directement
un wait() ?
public class Holder {
private int value;
private boolean done;
private final Object lock = new Object();
private void init() {
synchronized(lock) {
value = 12;
done = true;
lock.notify();
}
}
private void display() {
synchronized(lock) {
while(!done) {
lock.wait();
}
System.out.println(holder.value);
}
}
public static void main(String[] args) {
...
}
}
Le problème est que dans ce cas si
la thread exécute le notify() avant que
la thread main soit dans le wait(),
le notify() est perdu
Et le wait() va attendre indéfiniment !
Notification perdu et condition
Pour éviter les notifications perdu et donc d'attendre
indéfiniment dans le wait()
– Il faut qu'un champ change de valeur
Comme cela, on peut détecter si il faut faire le wait()
ou pas
– Bien sûr, ce champs doit être modifié uniquement dans
des blocs synchronized.
On appel le champ la condition du wait()
Pourquoi pas un if ?
public class Holder {
private int value;
private boolean done;
private final Object lock = new Object();
private void init() {
synchronized(lock) {
value = 12;
done = true;
lock.notify();
}
}
private void display() {
synchronized(lock) {
if(!done) {
lock.wait();
}
System.out.println(holder.value);
}
}
public static void main(String[] args) {
...
}
}
Car on n'est pas protégé
contre les spurious wakeups
While condition + wait
Un wait() n'est jamais tout seul,
Il est toujours dans un while sur une condition
Exemple:
while(stack.isEmpty()) {
lock.wait();
}
Et avec des ReentrantLock ?
On ne peut pas utiliser foo.wait()/foo.notify() car il
suppose synchronized(foo)
A partir d'un ReentrantLock
Condition condition = reentrantLock.newCondition();
– wait: condition.await()
– notify: condition.signal()
– notifyAll: condition.signalAll()
Await/signal
condition.await() marche exactement comme
object.wait() donc
– Lors de l'attente, le ReentrantLock à partir duquel la Condition
a été créée est relacher
– Puis si
● Une autre thread appel signal(), signalAll() ou interrupt(), ou alors à
cause d'un spurious wake-up
– la thread est réveillé et tente re-acquerir le ReentrantLock
condition.signal()/signalAll() marche comme
object.notify/notifyAll donc
– Il ne peuvent être exécuter que si la thread courante possède
le ReentrantLock à partir duquel la Condition a été créeé
Avec ReentrantLock.newCondition()
public class Holder {
private int value;
private boolean done;
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private void init() {
lock.lock();
try {
value = 12;
done = true;
condition.signal();
} finally {
lock.unlock();
}
}
private void display() {
lock.lock();
try {
while(!done) {
condition.await();
}
System.out.println(holder.value);
}
} finally {
lock.unlock();
}
...
}
On créé la Condition sur le ReentrantLock
On utilise signal() et await() que
entre lock() et unlock()
Condition
Contrairement à synchronized + wait/notify,
l'API des Condition permet de créer plusieurs
conditions pour un même ReentrantLock
Pratique pour indiquer des conditons qui ont
lieu par rapport à un même champs
– Par ex: pile pleine, pile vide
Exemple
J'ai 5 threads que je veux démarrer et mettre en
attente toute sur une barrière
– Par exemple, pour simuler un jeu en tour par tour
Si une thread atteint la barrière
– Elle est bloquée tant que les autres threads n'ont
pas atteint la barrière
– La dernière thread qui atteint la barrière, libère
toutes les autres threads en attente
Comment procéder ?
Une thread doit attendre au moins une autre
donc
– synchronized + wait/notify ou alors
– ReentrantLock + Condition + await/signal
Que faut-il d'autre ?
Comment procéder ? (2/2)
Une thread doit attendre au moins une autre
donc
– synchronized + wait/notify ou alors
– ReentrantLock + Condition + await/signal
Que faut-il d'autre ?
Une variable qui sert de condition !!!
Exemple / Code
public class Barrier {
private int party;
public Barrier(int party) {
this.party = party;
}
public void waitAt() {
// réveille les autres threads si c'est la dernière
// arrète la thread si ce n'est pas la dernière
}
}
Exemple / Code (2/3)
public class Barrier {
private int party;
private final Object lock = new Object();
public Barrier(int party) {
this.party = party;
}
public void waitAt() throws InterruptedException {
synchronized(lock) {
party--;
if (party == 0) {
lock.notifyAll();
return;
}
while (party != 0) {
lock.wait();
}
}
}
}
Et si ...
On veut que si l'on interrompt une thread
participant à la barrière, alors les autres doivent
aussi lever une InterruptedException
Exemple / Code (3/3)
public class Barrier {
private int party;
private boolean interrupted;
private final Object lock = new Object();
...
public void waitAt() throws InterruptedException {
synchronized(lock) {
party--;
if (party == 0) {
lock.notifyAll();
return;
}
while (!interrupted && party != 0) {
try {
lock.wait();
} catch(InterruptedException e) {
interrupted = true;
lock.notifyAll();
throw e;
}
}
if (interrupted) {
throw new InterruptedException();
}
}
}
}
On ajoute un flag pour savoir lorsque
l'on est reveillé si c'est parce que
toutes les threads ont atteint la barrière
ou si c'est parce qu'une des threads
a été interrompu

Contenu connexe

Similaire à 12-Concurrence-Rendez-vous.pdf

Comment écrire du code testable ?
Comment écrire du code testable ?Comment écrire du code testable ?
Comment écrire du code testable ?Fou Cha
 
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()Lorraine JUG
 
programmation réseau en java
programmation réseau en java programmation réseau en java
programmation réseau en java Ezéquiel Tsagué
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryneuros
 
Java - programmation concurrente
Java - programmation concurrenteJava - programmation concurrente
Java - programmation concurrenteFranck SIMON
 
Javascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJavascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJean-Pierre Vincent
 
Ateliers protypage d objets connectes via arduino
Ateliers protypage d objets connectes via arduinoAteliers protypage d objets connectes via arduino
Ateliers protypage d objets connectes via arduinoFatima Zahra Fagroud
 
Stream processing en mémoire avec Hazelcast Jet par Claire VILLARD
Stream processing en mémoire avec Hazelcast Jet par Claire VILLARDStream processing en mémoire avec Hazelcast Jet par Claire VILLARD
Stream processing en mémoire avec Hazelcast Jet par Claire VILLARDLa Cuisine du Web
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScriptMicrosoft
 
Fondamentaux portée - contexte - function ms tech days
Fondamentaux   portée - contexte - function ms tech daysFondamentaux   portée - contexte - function ms tech days
Fondamentaux portée - contexte - function ms tech daysJean-Pierre Vincent
 
15-Concurrence-Operations-Atomiques.pdf
15-Concurrence-Operations-Atomiques.pdf15-Concurrence-Operations-Atomiques.pdf
15-Concurrence-Operations-Atomiques.pdfPatiento Del Mar
 
Introduction to prograaming using ajax PHP JS
Introduction to prograaming using ajax PHP JSIntroduction to prograaming using ajax PHP JS
Introduction to prograaming using ajax PHP JSAliHusseini14
 
Javascript #4.2 : fonctions for pgm
Javascript #4.2 : fonctions for pgmJavascript #4.2 : fonctions for pgm
Javascript #4.2 : fonctions for pgmJean Michel
 
Chap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdfChap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdframadanmahdi
 

Similaire à 12-Concurrence-Rendez-vous.pdf (20)

threads.pdf
threads.pdfthreads.pdf
threads.pdf
 
Comment écrire du code testable ?
Comment écrire du code testable ?Comment écrire du code testable ?
Comment écrire du code testable ?
 
De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()De Runnable & synchronized à parallele() et atomically()
De Runnable & synchronized à parallele() et atomically()
 
Reseau
ReseauReseau
Reseau
 
programmation réseau en java
programmation réseau en java programmation réseau en java
programmation réseau en java
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jquery
 
Java - programmation concurrente
Java - programmation concurrenteJava - programmation concurrente
Java - programmation concurrente
 
Javascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJavascript : fondamentaux et OOP
Javascript : fondamentaux et OOP
 
Ateliers protypage d objets connectes via arduino
Ateliers protypage d objets connectes via arduinoAteliers protypage d objets connectes via arduino
Ateliers protypage d objets connectes via arduino
 
Stream processing en mémoire avec Hazelcast Jet par Claire VILLARD
Stream processing en mémoire avec Hazelcast Jet par Claire VILLARDStream processing en mémoire avec Hazelcast Jet par Claire VILLARD
Stream processing en mémoire avec Hazelcast Jet par Claire VILLARD
 
Introduction à JavaScript
Introduction à JavaScriptIntroduction à JavaScript
Introduction à JavaScript
 
Fondamentaux portée - contexte - function ms tech days
Fondamentaux   portée - contexte - function ms tech daysFondamentaux   portée - contexte - function ms tech days
Fondamentaux portée - contexte - function ms tech days
 
synchronization.pdf
synchronization.pdfsynchronization.pdf
synchronization.pdf
 
Cours design pattern m youssfi partie 4 composite
Cours design pattern m youssfi partie 4 compositeCours design pattern m youssfi partie 4 composite
Cours design pattern m youssfi partie 4 composite
 
Serveur http
Serveur httpServeur http
Serveur http
 
15-Concurrence-Operations-Atomiques.pdf
15-Concurrence-Operations-Atomiques.pdf15-Concurrence-Operations-Atomiques.pdf
15-Concurrence-Operations-Atomiques.pdf
 
module_I6_Sockets.pdf
module_I6_Sockets.pdfmodule_I6_Sockets.pdf
module_I6_Sockets.pdf
 
Introduction to prograaming using ajax PHP JS
Introduction to prograaming using ajax PHP JSIntroduction to prograaming using ajax PHP JS
Introduction to prograaming using ajax PHP JS
 
Javascript #4.2 : fonctions for pgm
Javascript #4.2 : fonctions for pgmJavascript #4.2 : fonctions for pgm
Javascript #4.2 : fonctions for pgm
 
Chap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdfChap 2--POO avec JAVA.pdf
Chap 2--POO avec JAVA.pdf
 

Plus de Patiento Del Mar

Plus de Patiento Del Mar (16)

Managed Extenibility Framework in C# - MEF
Managed Extenibility Framework  in C#  - MEFManaged Extenibility Framework  in C#  - MEF
Managed Extenibility Framework in C# - MEF
 
grpc_tutorial.pdf
grpc_tutorial.pdfgrpc_tutorial.pdf
grpc_tutorial.pdf
 
0.coursGitEclipse.pdf
0.coursGitEclipse.pdf0.coursGitEclipse.pdf
0.coursGitEclipse.pdf
 
Primefaces.ppt
Primefaces.pptPrimefaces.ppt
Primefaces.ppt
 
hibernateormoverview-140501154227-phpapp02.pdf
hibernateormoverview-140501154227-phpapp02.pdfhibernateormoverview-140501154227-phpapp02.pdf
hibernateormoverview-140501154227-phpapp02.pdf
 
hibernateormfeatures-140223193044-phpapp02.pdf
hibernateormfeatures-140223193044-phpapp02.pdfhibernateormfeatures-140223193044-phpapp02.pdf
hibernateormfeatures-140223193044-phpapp02.pdf
 
Spring Data Advanced Querying.ppt
Spring Data Advanced Querying.pptSpring Data Advanced Querying.ppt
Spring Data Advanced Querying.ppt
 
Thymeleaf and Spring Controllers.ppt
Thymeleaf and Spring Controllers.pptThymeleaf and Spring Controllers.ppt
Thymeleaf and Spring Controllers.ppt
 
Spring Security.ppt
Spring Security.pptSpring Security.ppt
Spring Security.ppt
 
momjms.pdf
momjms.pdfmomjms.pdf
momjms.pdf
 
rmi.pdf
rmi.pdfrmi.pdf
rmi.pdf
 
cours6.pdf
cours6.pdfcours6.pdf
cours6.pdf
 
java_PAR.pdf
java_PAR.pdfjava_PAR.pdf
java_PAR.pdf
 
22-reflection.pdf
22-reflection.pdf22-reflection.pdf
22-reflection.pdf
 
13-Concurrence-Producteur-consommateur.pdf
13-Concurrence-Producteur-consommateur.pdf13-Concurrence-Producteur-consommateur.pdf
13-Concurrence-Producteur-consommateur.pdf
 
Chap7_JavaNet.pdf
Chap7_JavaNet.pdfChap7_JavaNet.pdf
Chap7_JavaNet.pdf
 

12-Concurrence-Rendez-vous.pdf

  • 2. Echange d'information Si deux threads veulent s'échanger des données – Les données vont transitées par le tas (dans des champs) – Il faudra une ou plusieurs sections critiques pour éviter les états incohérents mais ce n'est pas suffisant, il faut aussi que la thread qui veut recevoir des données soit mis en attente
  • 3. Exemple Qu'affiche ce code ? public class Holder { private int value; public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { holder.value = 12; }).start(); System.out.println(holder.value); } }
  • 4. Exemple (suite) Trouver les 2 bugs ! public class Holder { private int value; private boolean done; public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { holder.value = 12; holder.done = true; }).start(); while(!holder.done) { // ne rien faire ! } System.out.println(holder.value); } }
  • 5. Exemple (suite/2) Bug 1: attente active, le CPU tourne en boucle public class Holder { private int value; private boolean done; public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { holder.value = 12; holder.done = true; }).start(); while(!holder.done) { // ne rien faire ! } System.out.println(holder.value); } } On réchauffe la planète
  • 6. Exemple (suite/2) Bug 1: attente active, le CPU tourne en boucle public class Holder { private int value; private boolean done; public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { holder.value = 12; holder.done = true; }).start(); while(!holder.done) { // ne rien faire ! } System.out.println(holder.value); } } On réchauffe la planète
  • 7. Exemple (suite/3) Bug 2: Le JIT peut introduire un registre pour la valeur holder.done public class Holder { private int value; private boolean done; public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { holder.value = 12; holder.done = true; }).start(); boolean r0 = holder.done; while(!r0) { // ne rien faire ! } System.out.println(holder.value); } } Oups
  • 8. Exemple (suite/4) Bug 2 bis: Le JIT ou le CPU peut ré-organiser les deux assignations public class Holder { private int value; private boolean done; public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { holder.done = true; // holder.value = 12; holder.value = 12; // holder.done = true; }).start(); while(!holder.done) { // ne rien faire ! } System.out.println(holder.value); } } Oups
  • 9. Exemple (suite/5) Un section critique résoud le bug 2 public class Holder { private int value; private boolean done; private final Object lock = new Object(); public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { synchronized(holder.lock) { holder.value = 12; holder.done = true; } }).start(); for(;;) { synchronized(holder.lock) { if (holder.done) { break; } } } synchronized(holder.lock) { System.out.println(holder.value); } } } Attention il faut bien les 2 blocs synchronized Et cela ne résoud pas le problème de l'attente active !
  • 10. Rendez vous On veut une façon d'arrêter une thread tant qu'une condition n'est pas vérifié – La thread en attente doit être dé-schédulée Lorque la condition est vrai, on veut réveillé la thread – La thread en attente doit être re-scédulée Ce mécanisme doit marcher avec les sections critiques car sinon on a les problèmes de visibilité, reorganisation, etc classique
  • 11. Exemple de wait()/notify() (mais pas objet) public class Holder { private int value; private boolean done; private final Object lock = new Object(); public static void main(String[] args) { Holder holder = new Holder(); new Thread(() -> { synchronized(holder.lock) { holder.value = 12; holder.done = true; holder.lock.notify(); } }).start(); synchronized(holder.lock) { while(!holder.done) { holder.lock.wait(); } System.out.println(holder.value); } } } Demande de mettre la thread en attente Reveil la thread si en attente sinon ne fait rien
  • 12. Exemple de wait()/notify() (version objet !) public class Holder { private int value; private boolean done; private final Object lock = new Object(); private void init() { synchronized(lock) { value = 12; done = true; lock.notify(); } } private void display() { synchronized(lock) { while(!done) { lock.wait(); } System.out.println(holder.value); } } ● public static void main(String[] args) { Holder holder = new Holder(); new Thread(holder::init).start(); holder.display(); } } Demande de mettre la thread en attente Reveil la thread si en attente sinon ne fait rien
  • 13. wait() object.wait() – demande à arréter la thread courante ● Celle-ci est de-schedulé – re-donne le moniteur associé à l'objet une fois la thread “reveillé” – re-prend le moniteur associé à l'objet – demande à reprendre la thread ● La thread est re-schédulé
  • 14. Conditions de reveil Comment une thread peut être reveillé d'un foo.wait() ? – Si une autre thread appel foo.notify() ou foo.notifyAll() – Si une autre thread interrompt la thread courante avec interrupt() ● dans ce cas foo.wait() lève InterruptedException – Sans raison apparente (spurious wake-up)
  • 15. notify() / notifyAll() foo.notify() – Demande le réveil d'une thread en attente sur foo avec un foo.wait() – Si aucune thread est en attente, le notify() est perdu et il ne se passe rien foo.notifyAll() – Demande le réveil de toutes les thread en attente sur foo avec un foo.wait()
  • 16. Wait/notify et synchonized foo.wait() ou foo.notify() ne peut être appelé que à l'intérieur d'un bloc synchonized sur foo – Pour wait(), c'est parce que wait() rend le moniteur associé à l'objet après avoir endormi la thread courante puis reprend le moniteur lorsque la thread est réveillé et sort du wait() – Pour notify(), c'est pour permettre à ce que la condition et le notify() soit atomique du point de vue des autres threads
  • 17. Pourquoi un while sur une valeur ? public class Holder { private int value; private boolean done; private final Object lock = new Object(); private void init() { synchronized(lock) { value = 12; done = true; lock.notify(); } } private void display() { synchronized(lock) { while(!done) { lock.wait(); } System.out.println(holder.value); } } public static void main(String[] args) { ... } } Pourquoi il faut absolument un while sur une valeur ?
  • 18. Pourquoi pas directement un wait() ? public class Holder { private int value; private boolean done; private final Object lock = new Object(); private void init() { synchronized(lock) { value = 12; done = true; lock.notify(); } } private void display() { synchronized(lock) { while(!done) { lock.wait(); } System.out.println(holder.value); } } public static void main(String[] args) { ... } } Le problème est que dans ce cas si la thread exécute le notify() avant que la thread main soit dans le wait(), le notify() est perdu Et le wait() va attendre indéfiniment !
  • 19. Notification perdu et condition Pour éviter les notifications perdu et donc d'attendre indéfiniment dans le wait() – Il faut qu'un champ change de valeur Comme cela, on peut détecter si il faut faire le wait() ou pas – Bien sûr, ce champs doit être modifié uniquement dans des blocs synchronized. On appel le champ la condition du wait()
  • 20. Pourquoi pas un if ? public class Holder { private int value; private boolean done; private final Object lock = new Object(); private void init() { synchronized(lock) { value = 12; done = true; lock.notify(); } } private void display() { synchronized(lock) { if(!done) { lock.wait(); } System.out.println(holder.value); } } public static void main(String[] args) { ... } } Car on n'est pas protégé contre les spurious wakeups
  • 21. While condition + wait Un wait() n'est jamais tout seul, Il est toujours dans un while sur une condition Exemple: while(stack.isEmpty()) { lock.wait(); }
  • 22. Et avec des ReentrantLock ? On ne peut pas utiliser foo.wait()/foo.notify() car il suppose synchronized(foo) A partir d'un ReentrantLock Condition condition = reentrantLock.newCondition(); – wait: condition.await() – notify: condition.signal() – notifyAll: condition.signalAll()
  • 23. Await/signal condition.await() marche exactement comme object.wait() donc – Lors de l'attente, le ReentrantLock à partir duquel la Condition a été créée est relacher – Puis si ● Une autre thread appel signal(), signalAll() ou interrupt(), ou alors à cause d'un spurious wake-up – la thread est réveillé et tente re-acquerir le ReentrantLock condition.signal()/signalAll() marche comme object.notify/notifyAll donc – Il ne peuvent être exécuter que si la thread courante possède le ReentrantLock à partir duquel la Condition a été créeé
  • 24. Avec ReentrantLock.newCondition() public class Holder { private int value; private boolean done; private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private void init() { lock.lock(); try { value = 12; done = true; condition.signal(); } finally { lock.unlock(); } } private void display() { lock.lock(); try { while(!done) { condition.await(); } System.out.println(holder.value); } } finally { lock.unlock(); } ... } On créé la Condition sur le ReentrantLock On utilise signal() et await() que entre lock() et unlock()
  • 25. Condition Contrairement à synchronized + wait/notify, l'API des Condition permet de créer plusieurs conditions pour un même ReentrantLock Pratique pour indiquer des conditons qui ont lieu par rapport à un même champs – Par ex: pile pleine, pile vide
  • 26. Exemple J'ai 5 threads que je veux démarrer et mettre en attente toute sur une barrière – Par exemple, pour simuler un jeu en tour par tour Si une thread atteint la barrière – Elle est bloquée tant que les autres threads n'ont pas atteint la barrière – La dernière thread qui atteint la barrière, libère toutes les autres threads en attente
  • 27. Comment procéder ? Une thread doit attendre au moins une autre donc – synchronized + wait/notify ou alors – ReentrantLock + Condition + await/signal Que faut-il d'autre ?
  • 28. Comment procéder ? (2/2) Une thread doit attendre au moins une autre donc – synchronized + wait/notify ou alors – ReentrantLock + Condition + await/signal Que faut-il d'autre ? Une variable qui sert de condition !!!
  • 29. Exemple / Code public class Barrier { private int party; public Barrier(int party) { this.party = party; } public void waitAt() { // réveille les autres threads si c'est la dernière // arrète la thread si ce n'est pas la dernière } }
  • 30. Exemple / Code (2/3) public class Barrier { private int party; private final Object lock = new Object(); public Barrier(int party) { this.party = party; } public void waitAt() throws InterruptedException { synchronized(lock) { party--; if (party == 0) { lock.notifyAll(); return; } while (party != 0) { lock.wait(); } } } }
  • 31. Et si ... On veut que si l'on interrompt une thread participant à la barrière, alors les autres doivent aussi lever une InterruptedException
  • 32. Exemple / Code (3/3) public class Barrier { private int party; private boolean interrupted; private final Object lock = new Object(); ... public void waitAt() throws InterruptedException { synchronized(lock) { party--; if (party == 0) { lock.notifyAll(); return; } while (!interrupted && party != 0) { try { lock.wait(); } catch(InterruptedException e) { interrupted = true; lock.notifyAll(); throw e; } } if (interrupted) { throw new InterruptedException(); } } } } On ajoute un flag pour savoir lorsque l'on est reveillé si c'est parce que toutes les threads ont atteint la barrière ou si c'est parce qu'une des threads a été interrompu