Cette question concerne les collections Java - spécifiquement hashtable et vecteur - mais peut également s'appliquer ailleurs.
J'ai lu dans de nombreux endroits à quel point il est bon de programmer des interfaces et je suis d'accord à 100%. La possibilité de programmer une interface de liste, par exemple, sans égard à la mise en œuvre sous-jacente, est très utile à des fins de découplage et de test. Avec des collections, je peux voir comment une arrachelist et une liste linité sont applicables sous différentes circonstances, compte tenu des différences par rapport à la structure de stockage interne, des temps d'accès aléatoires, etc. Cependant, ces deux implémentations peuvent être utilisées sous la même interface ... qui C'est génial. P>
Ce que je ne semble pas sembler placer, c'est la manière dont certaines implémentations synchronisées (en particulier hashable et vecteur) s'adaptent à ces interfaces. Pour moi, ils ne semblent pas adapter le modèle. La plupart des implémentations de structure de données sous-jacentes semblent varier dans la manière dont les données sont stockées (liaison LinkedList, Array, arborescence triée, etc.), tandis que la synchronisation traite des conditions (conditions de verrouillage) dans lesquelles les données peuvent être consultées. Regardons un exemple dans lequel une méthode renvoie une collection de cartes: p> supposons que l'application n'est pas concernée du tout avec une concurrence. Dans ce cas, nous opérons sur toute mise en œuvre de la méthode renvoie via l'interface ... tout le monde est heureux. Le monde est stable. p> Cependant, si l'application nécessite maintenant une attention sur le front de la concurrence? Nous ne pouvons maintenant pas utiliser sans tenir compte de la mise en œuvre sous-jacente - Hashtable irait bien, mais d'autres implémentations doivent être prises pour la tâche. Examinons 3 scénarios: p> 1) appliquer la synchronisation à l'aide de blocs de synchronisation, etc. Lorsque vous ajoutez / supprimé avec la collection. Cela ne serait toutefois pas survenir dans le cas où une implémentation synchronisée (hachage) est retournée? P> 2) Modifiez la signature de la méthode pour renvoyer la haquetable. Ceci, cependant, nous lie étroitement à la mise en œuvre de la hausse et, par conséquent, les avantages de la programmation à une interface sont projetés la fenêtre. P> 3) Utilisez le package simultané et modifiez la signature de la méthode pour retourner une implémentation de l'interface ConcurrentMap. Pour moi, cela ressemble à la voie à suivre. P> Essentiellement, il semble que certaines implémentations synchronisées soient un peu malfitant dans le cadre de collections en ce sens, lors de la programmation pour les interfaces, le problème de synchronisation force presque une Penser à la mise en œuvre sous-jacente. p> suis-je complètement manquant le point ici? p> Merci. P> P>
4 Réponses :
Vecteur de Java CODE> HASHTABLETABLE CODE> Paquet de concurrence actuel précédent dans JDK 5. À l'époque
Vecteur Code> a été écrit, les gens pensaient que c'était Une bonne idée de le rendre synchronisé, puis ils ont probablement atteint le mur de performance dans l'utilisation de l'entreprise. La concurrence est certainement l'une de ces situations où la modularité de code à interface peut ne pas toujours fonctionner. P>
Il est un peu plus long que celui que: 1.4 a introduit un cadre de collections mis à jour avec Java.Util.Collections.synchronizedMap et vos amis qui ont été recommandés à être utilisés à la place de HASHTABLE. Puis 1,5 introduit dans tout le paquet simultané. Mais la hache est toujours jumelée autour des bibliothèques standard et sera probablement pour toujours ... L'approche Java semble être que la synchronisation est un détail de mise en œuvre et que les exigences en matière de mise en œuvre devraient être communiquées à travers la documentation non par le biais de déclarations de l'API.
Appuyé. Les deux classes sont historiques et je crois qu'ils remontent à Java 1.0. Je suis sûr qu'ils remontent à 1,2, mais je ne vois pas les APIS antiques en ligne.
@araqnid, la voie de «approche Java» est peinte de sang et de cicatrices de performance, de concurrence, etc. du fil des ans. Surtout depuis l'utilisation de l'utilisation du serveur, l'échelle a appuyé sur l'injection de dépendance, l'interface-interface, l'astronaute de l'architecture, par rapport au simple "nouveau vecteur ();"
Ce que vous avez du mal, c'est que dans un environnement multi-fileté, un client ne peut pas utiliser naïvement un objet qui a un état mutable et partagé. L'interface de collecte, par elle-même, ne vous indique rien de la manière dont l'objet peut être utilisé en toute sécurité. Le retour d'un concours peut donner des informations supplémentaires mais uniquement pour ce cas particulier. P>
Normalement, vous devez communiquer les problèmes de sécurité de thread séparément dans la documentation (par exemple, Javadoc) ou en utilisant des annotations personnalisées, comme décrit dans Java Concurrence dans la pratique. Le client de l'objet retourné devra utiliser son propre mécanisme de verrouillage ou celui que vous fournissez. L'interface est généralement orthogonale à la sécurité du fil. P>
Ce n'est pas un problème si le client sait que toutes les implémentations proviennent des implémentations simultanées, mais que les informations ne sont pas communiquées par l'interface elle-même. P>
1) Oui, il sera surchargé
2) correct, qui ne devrait pas être fait
3) dépend de la situation. P>
La chose est, comme vous le savez déjà, la programmation de l'interface décrit la demande de l'application (non de la manière dont il le fait, c'est la mise en œuvre) p>
La synchronisation a été supprimée des implémentations ultérieures (rappelez-vous, le vecteur et la hâte sont antérieurs à Java 1.2 la plus tard une arraylist et une HASMAP qui n'étaient pas synchronisées, mais toutes ont effectué des interfaces de liste et de carte respectivement), car ils entraînent une pénalité de performance dû à la synchronisation excessive. Par exemple, si vous utilisez un vecteur dans un seul fil, vous avez toujours une synchronisation dans ce fil unique. P>
Partage d'une source de données entre plusieurs threads est quelque chose à prendre en compte lorsque Voici où vous choisissez entre les options 1 ou 3 que vous avez mentionnées. Y aurait-il une synchronisation manuelle? Devrions-nous utiliser une interface synchronisée? Quelle version nous appuierons, etc. P>
Par exemple, si vous choisissez 1, vous pouvez également dans votre conception de rejeter certaines implémentations (c.-à-d. Vecteur) P>
La synchronisation des données n'est pas quelque chose qui se passe par "chance" que vous devez vraiment concevoir pour qu'il se produise correctement et ne causez pas plus de problèmes que ceux-ci résolvent. P>
Au cours de cette conception, vous devez faire attention aux options (les implémentations) et / ou à l'infrastructure sous-jacente que vous utiliserez. p>
Le moyen le plus simple d'éviter une synchronisation excessive est d'utiliser des données immuables et de ne pas partager vos données avec d'autres threads. p>
Quelque chose de très similaire à la première loi de la distribution de l'informatique de Martin Fowler: P>
"Par conséquent, nous arrivons à ma première loi de la conception de l'objet distribué: ne pas distribuer vos objets." em> p>
blockQuote>
La première loi d'applications multithreaded serait-elle: p>
première loi d'applications multithreaded: ne partagez pas vos données? em> p>
blockQuote>
:) p>
Note finale: le Collections La classe fournit une version "synchronisée" de certaines interfaces: p>
HASHTABLE et Vecteur est très vieux, de JDK 1.0. Ils prédisent les collections standard de JDK1.2 et ne doivent pas être utilisées dans le nouveau code depuis longtemps. Utilisez HASHMAP et ArrayList enveloppé par Collections.SynchronizedMap () ou Collections.SynchronizedList () < / a> à la place. P>
Vous pouvez voir la version lorsque quelque chose a été introduit dans la JDK dans les documents de l'API sous la balise depuis la balise. P>
Je pense que la clé est que l'ajout de quelques mots-clés code> synchronisés ici ou de votre programme ne fait pas votre programme. Même avec
java.util.concurrent code> collections, vous souhaitez les garder en tant que détails de mise en œuvre privés.