SlideShare une entreprise Scribd logo
1  sur  11
Télécharger pour lire hors ligne
Concurrence
producteur/consommateur
Rémi Forax
Un serveur Web
Client 1
Client 2
Client 3
Client n
Thread 1
Thread 2
Thread 3
Thread m
?
Comment adapter les traitements
si il y a plus de clients que de threads,
ou moins de client que de thread ?
Si aucun client ?
Client 1
Client 2
Client 3
Client n
Thread 1
Thread 2
Thread 3
Thread m
?
Les threads doivent être en attente !
Si trop de clients ?
Thread 1
Thread 2
Thread 3
Thread m
?
Les clients doivent être en attente
Client 1
Client 2
Client 3
Client n
Producteur / Consommateur
Design Pattern permettant
– D'arrêter un producteur si il n'y a pas de
consommateur
– D'arrêter un consommateur si il n'y a pas de
producteur
Astuce: on utilise un buffer intermédiaire
Producteur / Consommateur
Producteur 1
Producteur 2
buffer
Consommateur 1
Consommateur 2
mettre
mettre
prendre
prendre
On utilise un buffer intermédiaire,
une file (queue en anglais) dans laquelle
on va mettre des messages et prendre des message
Notez que la flèche est inversée !
Producteur / Consommateur
Producteur 1
Producteur 2
buffer
Consommateur 1
Consommateur 2
mettre
mettre
prendre
prendre
Si la file est vide,
– On met le consommateur en attente
Si la file est pleine,
– On met le producteur en attente
Implantation avec wait/notify
public class Buffer {
private final ArrayDeque<Message> buffer =
new ArrayDeque<>();
private final int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
}
public void put(Message message) {
synchronized(buffer) {
while(buffer.size() == capacity) {
buffer.wait();
}
buffer.addLast(message);
...
}
}
...
}
public Message take() {
synchronized(buffer) {
while(buffer.size() == 0) {
buffer.wait();
}
...
return buffer.removeFirst();
}
}
On peut utiliser buffer comme moniteur !
Implantation avec wait/notify
public class Buffer {
private final ArrayDeque<Message> buffer =
new ArrayDeque<>();
private final int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
}
public void put(Message message) throws IE{
synchronized(buffer) {
while(buffer.size() == capacity) {
buffer.wait();
}
buffer.addLast(message);
buffer.notifyAll();
}
}
...
}
public Message take() throws IE {
synchronized(buffer) {
while(buffer.size() == 0) {
buffer.wait();
}
buffer.notifyAll();
return buffer.removeFirst();
}
}
Et avec des locks ?
public class Buffer {
private final ArrayDeque<Message> buffer =
new ArrayDeque<>();
private final ReentrantLock lock = new ReentrantLock();
private final Condition isEmpty = lock.newCondition();
private final Condition isFull = lock.newCondition();
private final int capacity;
...
public void put(Message message) throws IE {
lock.lock();
try {
while(buffer.size() == capacity) {
isFull.await();
}
buffer.addLast(message);
isEmpty.signalAll();
} finally {
lock.unlock();
}
}
...
}
public Message take() throws IE {
lock.lock();
try {
while(buffer.size() == 0) {
isEmpty.await();
}
isFull.signalAll();
return buffer.removeFirst();
} finally {
lock.unlock();
}
}
j.u.c.BlockingQueue
Le buffer des producteurs/consommateurs est déjà
implanté en Java
Il existe plusieurs implantations implantant
l'interface BlockingQueue
– LinkedBlockingQueue
● Utilise une liste chainée (attention à fixer la taille)
– ArrayBlockingQueue
● Utilise un tableau circulaire (comme ArrayDeque)
– SynchronousQueue
● N'accepte qu'un seul élement -> debug

Contenu connexe

Plus de Patiento Del Mar

Plus de Patiento Del Mar (20)

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
 
synchronization.pdf
synchronization.pdfsynchronization.pdf
synchronization.pdf
 
cours6.pdf
cours6.pdfcours6.pdf
cours6.pdf
 
java_PAR.pdf
java_PAR.pdfjava_PAR.pdf
java_PAR.pdf
 
11-Concurrence-Section critiques.pdf
11-Concurrence-Section critiques.pdf11-Concurrence-Section critiques.pdf
11-Concurrence-Section critiques.pdf
 
22-reflection.pdf
22-reflection.pdf22-reflection.pdf
22-reflection.pdf
 
16-Concurrence-APIs-Concurrentes.pdf
16-Concurrence-APIs-Concurrentes.pdf16-Concurrence-APIs-Concurrentes.pdf
16-Concurrence-APIs-Concurrentes.pdf
 
12-Concurrence-Rendez-vous.pdf
12-Concurrence-Rendez-vous.pdf12-Concurrence-Rendez-vous.pdf
12-Concurrence-Rendez-vous.pdf
 
17-Concurrence-Fork-Join.pdf
17-Concurrence-Fork-Join.pdf17-Concurrence-Fork-Join.pdf
17-Concurrence-Fork-Join.pdf
 
15-Concurrence-Operations-Atomiques.pdf
15-Concurrence-Operations-Atomiques.pdf15-Concurrence-Operations-Atomiques.pdf
15-Concurrence-Operations-Atomiques.pdf
 

13-Concurrence-Producteur-consommateur.pdf

  • 2. Un serveur Web Client 1 Client 2 Client 3 Client n Thread 1 Thread 2 Thread 3 Thread m ? Comment adapter les traitements si il y a plus de clients que de threads, ou moins de client que de thread ?
  • 3. Si aucun client ? Client 1 Client 2 Client 3 Client n Thread 1 Thread 2 Thread 3 Thread m ? Les threads doivent être en attente !
  • 4. Si trop de clients ? Thread 1 Thread 2 Thread 3 Thread m ? Les clients doivent être en attente Client 1 Client 2 Client 3 Client n
  • 5. Producteur / Consommateur Design Pattern permettant – D'arrêter un producteur si il n'y a pas de consommateur – D'arrêter un consommateur si il n'y a pas de producteur Astuce: on utilise un buffer intermédiaire
  • 6. Producteur / Consommateur Producteur 1 Producteur 2 buffer Consommateur 1 Consommateur 2 mettre mettre prendre prendre On utilise un buffer intermédiaire, une file (queue en anglais) dans laquelle on va mettre des messages et prendre des message Notez que la flèche est inversée !
  • 7. Producteur / Consommateur Producteur 1 Producteur 2 buffer Consommateur 1 Consommateur 2 mettre mettre prendre prendre Si la file est vide, – On met le consommateur en attente Si la file est pleine, – On met le producteur en attente
  • 8. Implantation avec wait/notify public class Buffer { private final ArrayDeque<Message> buffer = new ArrayDeque<>(); private final int capacity; public Buffer(int capacity) { this.capacity = capacity; } public void put(Message message) { synchronized(buffer) { while(buffer.size() == capacity) { buffer.wait(); } buffer.addLast(message); ... } } ... } public Message take() { synchronized(buffer) { while(buffer.size() == 0) { buffer.wait(); } ... return buffer.removeFirst(); } } On peut utiliser buffer comme moniteur !
  • 9. Implantation avec wait/notify public class Buffer { private final ArrayDeque<Message> buffer = new ArrayDeque<>(); private final int capacity; public Buffer(int capacity) { this.capacity = capacity; } public void put(Message message) throws IE{ synchronized(buffer) { while(buffer.size() == capacity) { buffer.wait(); } buffer.addLast(message); buffer.notifyAll(); } } ... } public Message take() throws IE { synchronized(buffer) { while(buffer.size() == 0) { buffer.wait(); } buffer.notifyAll(); return buffer.removeFirst(); } }
  • 10. Et avec des locks ? public class Buffer { private final ArrayDeque<Message> buffer = new ArrayDeque<>(); private final ReentrantLock lock = new ReentrantLock(); private final Condition isEmpty = lock.newCondition(); private final Condition isFull = lock.newCondition(); private final int capacity; ... public void put(Message message) throws IE { lock.lock(); try { while(buffer.size() == capacity) { isFull.await(); } buffer.addLast(message); isEmpty.signalAll(); } finally { lock.unlock(); } } ... } public Message take() throws IE { lock.lock(); try { while(buffer.size() == 0) { isEmpty.await(); } isFull.signalAll(); return buffer.removeFirst(); } finally { lock.unlock(); } }
  • 11. j.u.c.BlockingQueue Le buffer des producteurs/consommateurs est déjà implanté en Java Il existe plusieurs implantations implantant l'interface BlockingQueue – LinkedBlockingQueue ● Utilise une liste chainée (attention à fixer la taille) – ArrayBlockingQueue ● Utilise un tableau circulaire (comme ArrayDeque) – SynchronousQueue ● N'accepte qu'un seul élement -> debug