Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Apprendre BlockingQueue et Ses Implémentations | Collections Synchronisées
Multithreading en Java
course content

Contenu du cours

Multithreading en Java

Multithreading en Java

1. Notions de Base du Multithreading
2. Collections Synchronisées
3. Mécanismes de Synchronisation de Haut Niveau
4. Meilleures Pratiques de Multithreading

book
BlockingQueue et Ses Implémentations

Implémentations de base de BlockingQueue

Nous ne passerons pas en revue chaque réalisation en détail, car cela prendrait beaucoup de temps, et il est peu probable que vous en ayez besoin de toutes. Je parlerai des concepts généraux et des constructeurs qu'ils ont.

Exemple de la vie réelle

Imaginez une usine où un fil, le producteur, crée des pièces, et un autre fil, le consommateur, les traite. Le producteur place les pièces dans une file d'attente, tandis que le consommateur les récupère et les traite à partir de la file d'attente. Si la file d'attente est à court de pièces, le consommateur attend que le producteur en ajoute d'autres. Inversement, si la file d'attente est pleine, le producteur attend que le consommateur libère de l'espace.

Remarque

Un peu plus bas, nous allons implémenter cette tâche en code.

Différences par rapport aux autres types de collections

Le BlockingQueue fournit une synchronisation automatisée, gérant l'accès des threads à la file d'attente sans nécessiter de synchronisation manuelle. Il prend également en charge les opérations de blocage pour l'ajout et la récupération d'éléments, une fonctionnalité non trouvée dans d'autres collections comme ArrayList ou LinkedList.

Implémentations de BlockingQueue

ArrayBlockingQueue : Une file d'attente à taille limitée qui utilise un tableau pour stocker les éléments.

java

Main

copy
123456789
// Constructor with fixed capacity BlockingQueue<String> queue1 = new ArrayBlockingQueue<>(5); // Constructor with fixed capacity and fair access BlockingQueue<String> queue2 = new ArrayBlockingQueue<>(5, true); // Constructor with fixed capacity and initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new ArrayBlockingQueue<>(5, false, initialElements);

Explication

Le paramètre true active une politique d'accès équitable en fournissant un ordre FIFO pour l'accès des threads.

LinkedBlockingQueueue : Une file d'attente basée sur des nœuds liés qui peut être restreinte ou non restreinte.

java

Main

copy
123456789
// Constructor without capacity bounds BlockingQueue<String> queue1 = new LinkedBlockingQueue<>(); // Constructor with fixed capacity BlockingQueue<String> queue2 = new LinkedBlockingQueue<>(5); // Constructor with initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new LinkedBlockingQueue<>(initialElements);

PriorityBlockingQueue: Une file d'attente non bornée et priorisée où les éléments sont récupérés selon leur ordre naturel ou tel que spécifié par un comparateur.

java

Main

copy
12345678910111213
// Constructor without initial capacity (default is 11) BlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>(); // Constructor with initial capacity BlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(5); // Constructor with initial capacity and comparator Comparator<Integer> comparator = Integer::compareTo; BlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(5, comparator); // Constructor with initial collection of elements Collection<Integer> initialElements = java.util.Arrays.asList(1, 3, 2); BlockingQueue<Integer> queue4 = new PriorityBlockingQueue<>(initialElements)

DelayQueue: Une file d'attente différée où les éléments ne peuvent être récupérés qu'après l'expiration de leur délai.

java

DelayedElement

java

DelayQueueConstructors

copy
123456789101112131415161718
class DelayedElement implements Delayed { private final long expirationTime; // The time when the element will be available public DelayedElement(long delay, TimeUnit unit) { this.expirationTime = System.currentTimeMillis() + unit.toMillis(delay); } @Override public long getDelay(TimeUnit unit) { long delay = expirationTime - System.currentTimeMillis(); // Calculate the remaining delay return unit.convert(delay, TimeUnit.MILLISECONDS); // Convert the delay to the specified time unit } @Override public int compareTo(Delayed o) { return Long.compare(this.expirationTime, ((DelayedElement) o).expirationTime); } }

Ce code démontre l'utilisation de la classe DelayedElement, qui implémente l'interface Delayed, et de la file d'attente différée DelayQueue en Java. La classe DelayedElement définit une méthode getDelay pour calculer le temps de délai restant et une méthode compareTo pour comparer les objets en fonction du temps d'expiration du délai.

La méthode main crée deux files d'attente : queue1, une file d'attente différée vide, et queue2, une file d'attente initialisée avec des éléments ayant un délai de 5 et 1 seconde, respectivement.

Les éléments dans DelayQueueue deviennent disponibles pour récupération après que le temps de délai spécifié soit écoulé.

SynchronousQueueue: Une file d'attente sans capacité, où chaque opération d'insertion doit attendre l'opération d'extraction correspondante et vice versa.

java

Main

copy
12345
// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);

Les principales méthodes de BlockingQueue :

Ajout d'éléments :

La méthode void put(E e) insère un élément dans la file d'attente, bloquant le thread si la file est pleine. Alternativement, la méthode boolean offer(E e, long timeout, TimeUnit unit) tente d'ajouter un élément à la file d'attente, en attendant le temps spécifié si la file est pleine.

java

Main

copy
1234567891011121314151617
public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { queue.put("Element 1"); // Insert the first element, no blocking. queue.put("Element 2"); // Insert the second element, no blocking. // Try to add the third element with a 2-second timeout. // Since the queue is full, it will wait for 2 seconds. boolean success = queue.offer("Element 3", 2, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }

Cet exemple démontre l'insertion de deux éléments dans un BlockingQueue sans blocage, suivie d'une tentative d'ajout d'un troisième élément avec un délai d'attente de 2 secondes en utilisant la méthode offer(), qui attendra si la file d'attente est pleine.

Récupération d'Élément :

La méthode E take() récupère et retourne un élément de la file d'attente, bloquant le thread si la file d'attente est vide. Alternativement, la méthode E poll(long timeout, TimeUnit unit) tente de récupérer un élément de la file d'attente, en attendant le temps spécifié si la file d'attente est vide.

java

Main

copy
1234567891011121314151617181920212223
public class BlockingQueueRetrievalExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Retrieve and remove the first element, no blocking since the queue is not empty String item1 = queue.take(); // Returns "Element 1" // Attempt to retrieve and remove the next element with a 2-second timeout String item2 = queue.poll(2, TimeUnit.SECONDS); // Returns "Element 2" // Attempt to retrieve an element when the queue is empty, this will block for 2 seconds String item3 = queue.poll(2, TimeUnit.SECONDS); // Returns `null` after timeout } catch (InterruptedException e) { e.printStackTrace(); } } }

Ce code ajoute deux éléments à un BlockingQueue, récupère et supprime immédiatement le premier élément, tente de récupérer l'élément suivant avec un délai d'attente de 2 secondes, et enfin essaie de récupérer un élément d'une file d'attente vide, ce qui entraîne un null après le délai d'attente.

Vérification et Suppression des Éléments :

La méthode boolean remove(Object o) supprime l'élément spécifié de la file d'attente s'il est présent. D'autre part, la méthode boolean contains(Object o) vérifie si l'élément spécifié est présent dans la file d'attente sans le supprimer.

java

Main

copy
1234567891011121314151617181920212223242526
public class BlockingQueueCheckRemoveExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Check if "Element 1" is in the queue, should return `true` boolean containsElement1 = queue.contains("Element 1"); // true // Remove "Element 1" from the queue, should return `true` boolean removedElement1 = queue.remove("Element 1"); // true // Check if "Element 1" is still in the queue, should return `false` boolean containsElement1AfterRemoval = queue.contains("Element 1"); // false // Try to remove an element that is not in the queue, should return `false` boolean removedElement3 = queue.remove("Element 3"); // false } catch (InterruptedException e) { e.printStackTrace(); } } }

Ce code ajoute deux éléments à un BlockingQueue, vérifie la présence de "Element 1", le supprime, vérifie à nouveau pour confirmer sa suppression, puis tente de supprimer un élément inexistant.

Interroge l'état de la file d'attente :

La méthode int size() renvoie le nombre d'éléments actuellement dans la file d'attente. Pour déterminer si la file d'attente est vide, vous pouvez utiliser la méthode boolean isEmpty(), qui vérifie si la file d'attente n'a pas d'éléments. Pour les files d'attente avec une capacité fixe, la méthode int remainingCapacity() fournit le nombre de places restantes disponibles dans la file d'attente.

java

Main

copy
123456789101112131415161718192021222324252627282930
public class BlockingQueueCapacityExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Get the number of elements in the queue int currentSize = queue.size(); // 2 // Check if the queue is empty boolean isQueueEmpty = queue.isEmpty(); // false // Get the remaining capacity in the queue int remainingSpace = queue.remainingCapacity(); // 1 // Add another element to fill the queue queue.put("Element 3"); // Check the size and remaining capacity after adding the third element currentSize = queue.size(); // 3 remainingSpace = queue.remainingCapacity(); // 0 } catch (InterruptedException e) { e.printStackTrace(); } } }

Ce code ajoute des éléments à une BlockingQueue, vérifie la taille actuelle, vérifie si la file d'attente est vide, et détermine la capacité restante, puis met à jour ces valeurs après avoir rempli complètement la file d'attente.

Réaliser un Exemple de la Vie Réelle en Code

😭 Limitations

Une limitation clé est la performance : en raison des opérations de verrouillage impliquées, la performance peut être réduite par rapport aux collections non synchronisées. De plus, les ressources peuvent devenir une préoccupation car les grandes files d'attente exigent plus de mémoire et de temps CPU pour gérer les verrous et les processus de synchronisation.

💪 Avantages

Du côté positif, le système est sécurisé en multithreading, offrant une communication sûre entre les threads sans nécessiter de gestion de synchronisation manuelle. Il simplifie également le code en évitant les constructions complexes de synchronisation et de blocage. De plus, la flexibilité des différentes implémentations de BlockingQueue signifie qu'elles peuvent être adaptées à divers scénarios d'utilisation.

1. Qu'est-ce qu'une BlockingQueue en Java ?

2. Quelles sont les principales méthodes de BlockingQueue pour bloquer un thread ?

3. À quoi sert BlockingQueue dans les applications multithread ?

Qu'est-ce qu'une BlockingQueue en Java ?

Qu'est-ce qu'une BlockingQueue en Java ?

Sélectionnez la réponse correcte

Quelles sont les principales méthodes de BlockingQueue pour bloquer un thread ?

Quelles sont les principales méthodes de BlockingQueue pour bloquer un thread ?

Sélectionnez la réponse correcte

À quoi sert BlockingQueue dans les applications multithread ?

À quoi sert BlockingQueue dans les applications multithread ?

Sélectionnez la réponse correcte

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 2. Chapitre 3
We're sorry to hear that something went wrong. What happened?
some-alt