Producteur/Consommateur est un design pattern qui permet de faire communiquer :
La difficulté est de pouvoir:
Lorsque la file est pleine, les producteurs restent bloqués en attentant que la file se vide.
La file bloquante est le seul mécanisme de synchronisation utilisé ici !
La file des producteurs/consommateurs est déjà
implantée en Java. Il existe plusieurs implémentations de l'interface BlockingQueue.
ArrayBlockingQueue :ArrayDeque).
LinkedBlockingQueue :SynchronousQueue :Extrait de la doc Java:
| Throws exception | Special value | Blocks | Times out | |
| Insert | add(e) |
offer(e) |
put(e) |
offer(e, time, unit) |
| Remove | remove() |
poll() |
take() |
poll(time, unit) |
| Examine | element() |
peek() |
- | - |
Dans le contexte du pattern producteur/consommateur, on n'utilise jamais les méthodes levant une exception ; et très rarement celles renvoyant une valeur spéciale.
BlockingQueue<String> queue = new ... // quelle implémentation ?
for (var i = 0; i < 3; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(100);
queue.put(Thread.currentThread().getName());
} catch (InterruptedException e) {
return;
}
}
});
}
for (var i = 0; i < 2; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(500);
System.out.println("next " + queue.take());
} catch (InterruptedException e) {
return;
}
}
});
}
BlockingQueue<String> queue = new ...
for (var i = 0; i < 3; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(100);
queue.put(Thread.currentThread().getName());
} catch (InterruptedException e) {
return;
}
}
});
}
for (var i = 0; i < 2; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(500);
if ( !queue.isEmpty() ){
System.out.println("next : " + queue.remove()); // idem avec queue.poll()
}
} catch (InterruptedException e) {
return;
}
}
});
}
var queue = new LinkedBlockingQueue<String>();
for (var i = 0; i < 3; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(100);
queue.put(Thread.currentThread().getName());
} catch (InterruptedException e) {
return;
}
}
});
}
for (var i = 0; i < 2; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(500);
System.out.println("next : " + queue.take());
} catch (InterruptedException e) {
return;
}
}
});
}
La file va grandir jusqu'à faire une OutOfMemoryError.
var queue = new ArrayBlockingQueue<String>(10);
for (var i = 0; i < 3; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(100);
queue.put(Thread.currentThread().getName());
} catch (InterruptedException e) {
return;
}
}
});
}
for (var i = 0; i < 2; i++) {
Thread.ofPlatform().start(() -> {
for(;;) {
try {
Thread.sleep(500);
System.out.println("next : " + queue.take());
} catch (InterruptedException e) {
return;
}
}
});
}
Plus de possiblité de OutOfMemoryError.