Pour l'instant, nous ne gérons pas les InteruptedException et rien dans votre code ne peut provoquer la levée de cette exception.
throws),
Runnable run = () -> {
try {
Thread.sleep(20_000);
} catch (InterruptedException e) {
// this should not happen !
throw new AssertionError(e);
}
};
On ne doit jamais voir e.printStackTrace();
BoundedSafeQueue
public class BoundedSafeQueue<V> {
private final ArrayDeque<V> queue = new ArrayDeque<>();
private final int capacity;
...
public void add(V value) throws InterruptedException {
Objects.requireNonNull(value);
synchronized (queue) {
while (queue.size() >= capacity) {
queue.wait();
}
queue.add(value);
queue.notify();
}
}
public V take() throws InterruptedException {
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait();
}
queue.notify();
return queue.remove();
}
}
Quel est le problème?
Supposons que 2 threads nommés t1 et t2 font des add et qu'un 3e thread, le main, fait des take, en continu, sur une file de capacité 1.
public class BoundedSafeQueue<V> {
private final ArrayDeque<V> queue = new ArrayDeque<>();
private final int capacity;
...
public void add(V value) throws InterruptedException {
Objects.requireNonNull(value);
synchronized (queue) {
while (queue.size() >= capacity) {
queue.wait();
}
queue.add(value);
queue.notifyAll();
}
}
public V take() throws InterruptedException {
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait();
}
queue.notifyAll();
return queue.remove();
}
}
Correction rapide
Dans cet exercice, on veut réaliser une classe Vote. Cette classe thread-safe permet d'enregistrer
n votes pour des String. Quand les n votes ont été enregistrés, on renvoie à chaque votant la String qui a reçu le plus de votes (en cas d'égalité, on renvoie la plus petite dans l'ordre alphabétique ayant reçu le plus de votes). Le nombre n de votes attendus est pris en paramètre par le constructeur.
La classe Vote offre une seule méthode vote qui sert à proposer son vote et qui bloque jusqu'à ce que les n votes soient arrivés. Ensuite elle
renvoie le gagnant. Si vote est appelée après que les n votes aient été reçus, la méthode renvoie simplement le gagnant.
On calcule le gagnant après que le vote soit fini (et que d'autres votants peuvent arriver) : si un votant arrive après la fin du vote, il peut modifier le résultat !
On recalcule le gagnant à chaque fois qu'une valeur est renvoyée.
On fait trop de notifications : si chaque thread qui sort d'un wait notifie tous les autres.
HashMapPour mettre à jour une HashMap<K,V> efficacement (V non mutable) :
map.merge(key, 1, Interger::sum); // ou map.merge(key, 1, (x,y) -> x + y);
équivaut à :
map.compute(key,(k, v) -> {
if (v == null) {
return 1;
} else {
return v + 1;
}
});
HashMapAu pire, si vous n'y arrivez pas avec une lambda (V toujours non mutable):
var oldValue = map.get(key); // fait office d'appel à map.contains(key)
if (oldValue == null) {
oldValue = initialValue;
}
map.put(key, update(oldValue)); // update est un UnaryOperator<V>
Ou mieux :
var oldValue = map.getOrDefault(key, 0); map.put(key, update(oldValue)); // update est un UnaryOperator<V>
HashMapPour mettre à jour une HashMap<K,V> efficacement (V mutable):
HashMap<Long,Data> map = ... var data = map.computeIfAbsent<(key, k -> new Data()); data.update(newValue);
Par exemple :
HashMap<String,ArrayList<Integer>> map = ... map.computeIfAbsent(key, k -> new ArrayList<>()).add(1);