374 votes

Y a-t-il une liste concurrente dans la JDK de Java?

Comment puis-je créer une instance de Liste concurrentielle, où je peux accéder aux éléments par index? Le JDK a-t-il des classes ou des méthodes d'usine que je peux utiliser?

30 votes

Pourquoi pas constructif? Plusieurs ont proposé CopyOnWriteArrayList qui n'est pas trouvée dans .Net. Vous pouvez dire que les deux questions sont liées mais ne pas fermer celle-ci !!!

0 votes

Dans .NET, l'équivalent de CopyOnWriteArrayList est Immutable Collections. Une collection concurrente est une collection qui ne nécessite pas de verrouillage pour être modifiée (comme ConcurrentQueue, etc.), et NON pas une collection qui copie son contenu à chaque fois qu'elle est copiée.

1 votes

Je n'ai aucune idée de pourquoi Jarrod Roberson penserait que ce serait une bonne idée de prendre les modifications détaillées apportées par Stephan et de les ramener à la question originale, mal formulée. La réponse de Jarrod reste néanmoins parfaitement acceptable. En fait, CopyOnWriteArrayList est la seule classe concurrente implémentant List dans le JDK. Perplexe...

253voto

Matt Passell Points 1247

ConcurrentLinkedQueue

Si vous ne vous souciez pas d'avoir un accès basé sur l'index et que vous voulez simplement conserver les caractéristiques de préservation de l'ordre d'insertion d'une liste, vous pouvez envisager un java.util.concurrent.ConcurrentLinkedQueue. Étant donné qu'il implémente Iterable, une fois que vous avez fini d'ajouter tous les éléments, vous pouvez parcourir le contenu en utilisant la syntaxe améliorée pour la boucle :

Queue globalQueue = new ConcurrentLinkedQueue();

//Plusieurs threads peuvent appeler globalQueue.add() en toute sécurité...

for (String href : globalQueue) {
    //faire quelque chose avec href
}

4 votes

Je pense que l'instruction simplifiée for (:) est appelée foreach : docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.htm‌​l

2 votes

@AlikElzin-kilaka Tu as raison. Je pense que ce nom m'a toujours dérangé, car la syntaxe réelle ne comprend pas le mot "each", mais je vais mettre à jour la réponse pour utiliser le nom officiel. :)

4 votes

@AlikElzin-kilaka Chipoter, mais selon la version JLS 8 il est appelé "l'instruction de for améliorée". De même dans le tutoriel java.

215voto

Jarrod Roberson Points 32263

Il existe une implémentation de liste concurrentielle dans java.util.concurrent : CopyOnWriteArrayList.

Il copie la liste pour "toutes les opérations mutatives (add, set, et ainsi de suite)", ce qui le rend plus performant pour les applications en lecture intensive.

104 votes

Veuillez noter qu'il copie toute la liste à chaque insertion, ce qui est souvent inefficace.

27 votes

@dfrankow Mais cela peut être encore plus efficace si vous itérez beaucoup plus que vous ne mettez à jour.

0 votes

Ne fonctionne pas bien comme indiqué ici. J'ai des exceptions même si j'utilise simplement sa méthode addAll et la lis en utilisant un flux. stackoverflow.com/questions/1527519/…

165voto

Yanick Rochon Points 18537

Avertissement : Cette réponse a été publiée en 2011, avant JDK 5, et avant de nombreuses API concurrentes avancées et optimales. Donc, bien que ce qui suit fonctionnera, ce n'est pas la meilleure option.


Vous pouvez très bien utiliser Collections.synchronizedList(List) si tout ce dont vous avez besoin est une synchronisation d'invocation simple :

 List objList = Collections.synchronizedList(new ArrayList());

87 votes

Le résultat de synchronizedList est "synchronisé" mais pas "concurrent". Un problème fondamental est que de nombreuses opérations de liste -- qui sont basées sur l'index -- ne sont pas elles-mêmes atomiques et doivent faire partie d'une plus grande structure d'exclusion mutuelle.

6 votes

À mon avis, l'attribution d'un Vector est plus simple que Collections.synchronizedList(new ArrayList()).

11 votes

Le résultat de synchronizedList est "synchronized" mais pas "concurrent".

62voto

Joachim Sauer Points 133411

Parce que l'acte d'acquérir la position et d'obtenir l'élément de la position donnée nécessite naturellement un certain verrouillage (vous ne pouvez pas avoir la liste subir des changements structurels entre ces deux opérations).

L'idée même d'une collection concurrente est que chaque opération en soi est atomique et peut être effectuée sans verrouillage/synchronisation explicite.

Par conséquent, obtenir l'élément à la position n d'une Liste donnée en tant qu'opération atomique n'a pas beaucoup de sens dans une situation où l'accès concurrent est anticipé.

8 votes

Joachim, je pense que tu as touché dans le mille. Prenez par exemple, une liste en lecture seule comme une liste concurrente. Obtenir l'élément à la position N de la liste a du sens, mais c'est là tout le problème. Donc, une liste immuable (minuscule L) serait un bon exemple, mais ce n'est pas une List (majuscule L). Le CopyOnWriteArrayList est concurrent, mais beaucoup de gens n'aiment pas ses performances. Une solution dans le style de ropes (cordes de chaîne) serait probablement un bon choix.

2 votes

Très bon point. Mais la liste que l'OP va utiliser pourrait avoir une utilisation très spécifique. Par exemple, elle pourrait être remplie dans un environnement concurrent, puis "verrouillée" (peu importe ce que cela signifie) et ensuite accédée en toute sécurité par index. Donc, dans la première phase de remplissage d'une telle liste, une implémentation thread-safe sera toujours nécessaire. Malheureusement, l'OP n'était pas spécifique sur la façon dont la liste qu'il recherche va être utilisée.

48voto

Oliv Points 828

Vous avez ces options :

  • Collections.synchronizedList() : vous pouvez envelopper n'importe quelle implémentation de List (ArrayList, LinkedList ou une liste tierce). L'accès à chaque méthode (lecture et écriture) sera protégé en utilisant synchronized. Lors de l'utilisation de iterator() ou de boucles améliorées, vous devez synchroniser manuellement toute l'itération. Pendant l'itération, les autres threads sont entièrement bloqués même pour la lecture. Vous pouvez également synchroniser séparément pour chaque appel à hasNext et next, mais alors ConcurrentModificationException est possible.

  • CopyOnWriteArrayList : il est coûteux de modifier, mais sans attente pour la lecture. Les itérateurs ne lancent jamais de ConcurrentModificationException, ils renvoient une capture de la liste au moment de la création de l'itérateur même si la liste est modifiée par un autre thread pendant l'itération. Utile pour les listes rarement mises à jour. Les opérations en bloc telles que addAll sont préférées pour les mises à jour - le tableau interne est copié moins de nombreuses fois.

  • Vector : très similaire à synchronizedList(new ArrayList<>()), mais l'itération est également synchronisée. Cependant, les itérateurs peuvent lancer ConcurrentModificationException si le vecteur est modifié par un autre thread pendant l'itération.

Autres options :

  • Queue ou Deque pourraient être une alternative si vous ajoutez/supprimez uniquement aux extrémités de la liste ou si vous l'itérez. Queue permet seulement d'ajouter à une extrémité et de supprimer de l'autre extrémité, Deque permet d'ajouter et de supprimer des deux extrémités. Il n'y a pas d'accès par index. Il existe plusieurs implémentations avec de meilleures propriétés de concurrence que toute List ne peut fournir. Regardez les "Toutes les classes implémentées connues" dans la javadoc de Queue, ces implémentations qui se trouvent dans le package java.util.concurrent sont concurrentes. Vous pouvez également jeter un œil à JCTools, il contient des implémentations de file plus rapides spécialisées pour un seul consommateur ou un seul producteur.
  • Collections.unmodifiableList() : sans attente, thread-safe, mais non modifiable
  • List.of & List.copyOf : Une autre liste non modifiable en Java 9 et ultérieur.

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