101 votes

Comment utiliser ConcurrentLinkedQueue?

Comment puis-je utiliser un ConcurrentLinkedQueue en Java?
L'utilisation de ce LinkedQueue, ai-je besoin d'être inquiet au sujet de la simultanéité dans la file d'attente? Ou dois-je définir deux méthodes (l'un à la restauration des éléments de la liste et un autre pour ajouter des éléments à la liste)?
Remarque: bien entendu, ces deux méthodes doivent être synchronisés. Droit?


EDIT: Ce que j'essaie de faire est ceci: j'ai une classe (en Java) avec une méthode pour récupérer les éléments de la file d'attente et une autre classe avec une méthode pour ajouter des éléments à la file d'attente. Les éléments ajoutés et récupérées à partir de la liste sont des objets de ma propre classe.

Encore une question: ai-je besoin de le faire dans la méthode remove:

while (queue.size() == 0){ 
  wait(); 
  queue.poll();
}

J'ai seulement un consommateur et un producteur.

161voto

Adam Jaskiewicz Points 7485

Non, les méthodes n'ont pas besoin d'être synchronisés, et vous n'avez pas besoin de définir toutes les méthodes; elles sont déjà en ConcurrentLinkedQueue, simplement les utiliser. ConcurrentLinkedQueue fait tout le verrouillage et le truc que vous avez besoin à l'interne; votre producteur(s) propose des trucs dans la file d'attente, et vos consommateurs sondage pour elle.

Tout d'abord, créez votre file d'attente:

Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();

Maintenant, partout où vous créez votre producteur/consommateur, les objets, les passer dans la file d'attente de sorte qu'ils ont un endroit pour mettre leurs objets (on peut utiliser un setter pour cela, à la place, mais je préfère faire ce genre de chose dans un constructeur):

YourProducer producer = new YourProducer(queue);

et:

YourConsumer consumer = new YourConsumer(queue);

et ajouter des trucs dans votre producteur:

queue.offer(myObject);

et de prendre des trucs dans votre consommateur (si la file d'attente est vide, poll() renvoie la valeur null, alors check it):

YourObject myObject = queue.poll();

Pour plus d'infos, consultez la Javadoc

EDIT:

Si vous avez besoin de bloquer en attente de la file d'attente pour ne pas être vide, vous voudrez probablement utiliser une LinkedBlockingQueue, et utilisez la méthode. Cependant, LinkedBlockingQueue a une capacité maximum (valeur par défaut Entier.MAX_VALUE, qui est plus de deux milliards de dollars) et de ce qui peut ou peut ne pas être appropriée selon votre cas.

Si vous n'avez qu'un seul thread mettre des trucs dans la file d'attente, et un autre thread de prendre des choses de la file d'attente, ConcurrentLinkingQueue est probablement excessif. C'est plus pour quand vous pouvez avoir des centaines ou même des milliers de threads d'accéder à la file d'attente en même temps. Vos besoins vont probablement être atteint en utilisant:

Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());

Un avantage de cela est que, il bloque sur l'instance (file d'attente), de sorte que vous pouvez synchroniser sur la file d'attente afin d'assurer l'atomicité de composite de l'exploitation (comme expliqué par Jared). Vous NE pouvez pas faire cela avec un ConcurrentLinkingQueue, puisque toutes les opérations sont effectuées SANS verrouillage de l'instance (à l'aide de java.util.de façon concomitante.atomique variables). Vous n'aurez PAS besoin de faire cela si vous voulez bloquer alors que la file d'attente est vide, parce que poll() renvoie simplement la valeur null alors que la file d'attente est vide, et poll() est atomique. Vérifiez pour voir si poll() renvoie la valeur null. Si elle le fait, wait(), puis essayez à nouveau. Pas besoin de le verrouiller.

Enfin:

Honnêtement, j'aimerais utiliser un LinkedBlockingQueue. Il est encore overkill pour votre application, mais les chances sont qu'il sera beau travail. Si elle n'est pas assez performant (PROFIL!), vous pouvez toujours essayer quelque chose d'autre, et cela signifie que vous n'avez pas à traiter avec TOUT synchronisé trucs:

BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();

queue.put(myObject); // Blocks until queue isn't full.

YourObject myObject = queue.take(); // Blocks until queue isn't empty.

Tout le reste est le même. Mettre probablement ne bloquera pas, parce que vous ne sont pas susceptibles de mettre deux milliards d'objets dans la file d'attente.

38voto

Jared Points 7800

C'est en grande partie un doublon d'une autre question.

Voici la section de la réponse pertinente à cette question:

Dois-je faire ma propre synchronisation si j'utilise java.util.ConcurrentLinkedQueue?

Les opérations atomiques sur le simultanées collections sont synchronisés pour vous. En d'autres termes, chaque appel à la file d'attente est garanti "thread-safe", sans aucune action de votre part. Ce n'est pas garanti thread-safe sont toutes les opérations que vous effectuez sur la collection sont non-atomique.

Par exemple, c'est thread-safe, sans aucune action de votre part:

queue.add(obj);

ou

queue.poll(obj);

Cependant, la non-atomique appels de la file d'attente ne sont pas automatiquement thread-safe. Par exemple, les opérations suivantes ne sont pas automatiquement des threads:

if(!queue.isEmpty()) {
   queue.poll(obj);
}

Ce dernier n'est pas thread-safe, car il est très possible qu'entre le moment isEmpty est appelée et le sondage est appelée, les autres threads avez ajouté ou supprimé des éléments de la file d'attente. Les threads pour effectuer ce est comme ceci:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}

Une fois de plus...atomique appels de la file d'attente sont automatiquement thread-safe. Non-atomique, les appels ne sont pas.

6voto

Hank Gay Points 36173

Utilisez poll pour obtenir le premier élément et ajoutez pour ajouter un nouveau dernier élément. C'est ça, pas de synchronisation ou quoi que ce soit d'autre.

2voto

siddhadev Points 6083

ConcurentLinkedQueue est une implémentation très efficace sans attente / verrouillage (voir le javadoc pour référence), donc non seulement vous n'avez pas besoin de synchroniser, mais la file d'attente ne verrouille rien, ce qui la rend pratiquement aussi rapide qu'un non synchronisé (pas de thread sûr) un.

1voto

Benoit Points 39210

Utilisez-le simplement comme une collection non simultanée. Les classes [Collection] simultanées encapsulent les collections régulières afin que vous n'ayez pas à vous préoccuper de la synchronisation des accès.

Edit: ConcurrentLinkedList n’est pas vraiment un wrapper, mais plutôt une meilleure implémentation simultanée. De toute façon, vous n'avez pas à vous soucier de la synchronisation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X