Le meilleur moyen de contrôler l'accès simultané à Java collections
Devrais-je utiliser de vieux synchronisé Vecteur de la collection, liste de tableaux avec synchronisation des accès ou des Collections.synchronizedList ou une autre solution pour l'accès simultané?
Je ne vois pas de réponse à ma question sur Questions Connexes, ni dans ma recherche (Faire vos collections thread-safe? n'est pas le même).
Récemment, j'ai dû faire en sorte de tests unitaires sur le GUI parties de notre application (essentiellement l'aide de l'API pour créer des images, ajouter des objets, etc.).
Parce que ces opérations est beaucoup plus rapide que par un utilisateur, il montre un certain nombre de problèmes avec les méthodes d'essayer d'accéder à des ressources n'est pas encore créé ou déjà supprimés.
Une question en particulier, qui se passe dans l'EDT, est venu de marcher une liste de points de vue tout en la modifiant dans un autre thread (obtention d'un ConcurrentModificationException parmi d'autres problèmes).
Ne me demandez pas pourquoi, c'était une liste liée au lieu d'une simple liste de tableau (encore moins que nous avons en général de 0 ou de 1. vue de l'intérieur...), donc j'ai pris le plus commun ArrayList dans ma question (car il a un cousin plus âgé).
De toute façon, pas super familier avec les problèmes de simultanéité, j'ai regardé un peu d'info, et je me demandais quoi choisir entre l'ancien (et probablement obsolète) Vecteur (qui a opérations synchronisées par conception), ArrayList avec un synchronized (myList) { }
autour des sections critiques (ajouter/supprimer/marche des opérations) ou à l'aide d'une liste renvoyée par les Collections.synchronizedList (même pas sûr de la façon d'utiliser le dernier).
J'ai finalement choisi la deuxième option, car une autre erreur a été d'exposer l'objet (getViewList (), méthode...) au lieu de fournir des mécanismes pour l'utiliser.
Mais quels sont les avantages et les inconvénients des autres approches?
[MODIFIER] Beaucoup de bons conseils ici, difficile d'en sélectionner un. Je vais choisir la plus détaillée et fournir des liens/la nourriture pour la pensée... 🙂 j'aime Darron l'un de l'autre.
Pour résumer:
- Comme je le soupçonnais, le Vecteur (et son jumeau maléfique, table de hachage ainsi, sans doute) est en grande partie obsolète, j'ai vu des gens dire à son ancien design n'est pas aussi bon que de nouvelles collections", au-delà de la lenteur de la synchronisation forcée, même dans un seul thread de l'environnement. Si nous le garder, c'est surtout parce que les anciennes bibliothèques (et certaines parties de l'API Java) toujours l'utiliser.
- Contrairement à ce que je pensais, Collections.synchronizedXxxx ne sont pas des plus modernes que le Vecteur (ils semblent être contemporain des Collections, c'est à dire. Java 1.2!) et pas mieux, en fait. Bon à savoir. En bref, je dois éviter d'eux ainsi.
- Synchronisation manuelle semble être une bonne solution, après tout. Il pourrait y avoir des problèmes de performance, mais dans mon cas, cela n'est pas grave: les opérations effectuées sur les actions de l'utilisateur, petite collection, pas d'un usage fréquent.
- java.util.simultanées paquet est utile de garder à l'esprit, en particulier la CopyOnWrite méthodes.
J'espère que j'ai bien compris... 🙂
- Voir aussi stackoverflow.com/questions/510632/...
Vous devez vous connecter pour publier un commentaire.
Vecteur et de la Liste renvoyée par les Collections.synchronizedList() sont moralement la même chose. Je le considère comme Vecteur d'être efficace (mais pas vraiment) obsolète et préférez toujours une synchronisé Liste à la place. La seule exception serait la vieille Api (surtout celles dans le JDK) qui nécessitent un Vecteur.
À l'aide d'un nu, liste de tableaux et de synchronisation de façon indépendante vous donne l'opportunité à plus de régler avec précision votre synchronisation (soit en incluant des actions supplémentaires dans le excluent mutuellement bloc ou en mettant ensemble plusieurs appels à la Liste atomique). L'inconvénient c'est qu'il est possible d'écrire du code qui accède à nu ArrayList en dehors de la synchronisation, qui est rompu.
Une autre option que vous pourriez envisager est une CopyOnWriteArrayList, qui vous donnera la sécurité des threads comme dans le Vecteur et synchronisé liste de tableaux mais aussi des itérateurs qui ne va pas jeter ConcurrentModificationException comme ils travaillent à l'extérieur d'un non-live instantané des données.
Vous pouvez trouver certains de ces dernières blogs sur ces sujets intéressants:
Je recommande fortement le livre "Java de la Simultanéité dans la Pratique".
Chaque choix a ses avantages/inconvénients:
Je ne peux pas penser à une bonne raison de jamais préférez
Vector
surArrayList
. Liste des opérations sur unVector
sont synchronisés, signifiant que plusieurs threads peuvent modifier en toute sécurité. Et comme tu le dis, ArrayList opérations peuvent être synchronisés à l'aide deCollections.synchronizedList
.N'oubliez pas que même lors de l'utilisation de listes synchronisées, vous rencontrerez toujours
ConcurrentModificationExceptions
si une itération sur la collection, tandis que c'est en cours de modification par un autre thread. Il est donc important de coordonner l'accès à l'extérieur (votre deuxième option).Une technique courante utilisée pour éviter l'itération problème est d'itérer sur immuable des exemplaires de la collection. Voir
Collections.unmodifiableList
je serais toujours aller à la java.util.simultanée (http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html) package d'abord et voir s'il est adapté de la collection. la java.util.de façon concomitante.CopyOnWriteArrayList classe est bon si vous faites quelques modifications à la liste, mais plus d'itérations.
aussi je ne crois pas que Vecteur et des Collections.synchronizedList permettra d'éviter ConcurrentModificationException.
si vous ne trouvez pas approprié de collecte alors que vous avez à faire votre propre synchronisation, et si vous ne voulez pas placer un verrou lors de l'itération, vous pouvez envisager de faire une copie et l'itération de la copie.
Je ne crois pas que la
Iterator
retourné par un Vecteur est en aucune façon synchronisée - ce qui signifie queVector
ne peux pas le garantir (lui-même) qu'un thread n'est pas la modification de la collection sous-jacente, tandis qu'un autre thread est une itération à travers elle.Je crois que pour s'assurer que l'itération est thread-safe, vous devrez gérer la synchronisation sur votre propre. En supposant que le Vecteur/Liste/objet est partagé par plusieurs threads (et donc conduisant à vos questions), tu ne peux pas synchroniser sur l'objet lui-même?
La solution la plus sûre est d'éviter les accès concurrents aux données partagées au total. Au lieu d'avoir non-HAE threads fonctionnent sur les mêmes données, les faire appeler
SwingUtilities.invokeLater()
avec un Exécutable qui effectue les modifications apportées.Au sérieux et de partage de données de simultanéité est une vipère du nid où vous ne saurez jamais si il n'y a pas d'autre condition de course ou de blocage cacher quelque part, biding son temps à vous mordre dans le cul et dans les pires occasion.
CopyOnWriteArrayList vaut la peine de regarder. Il est conçu pour une liste qui est généralement de lire. Chaque écriture serait la cause pour créer un nouveau tableau derrière le couvre de sorte que ceux de l'itération à travers le tableau ne serait pas obtenir un ConcurrentModificationException