11
votes

Reentrantreadwritelock - Beaucoup de lecteurs à la fois, un écrivain à la fois?

Je suis un peu nouveau dans des environnements multithreads et j'essaie de trouver la meilleure solution pour la situation suivante:

J'ai lu des données d'une base de données une fois par jour le matin et stocke les données dans un hashmap dans un objet singleton. J'ai une méthode de setter qui s'appelle uniquement lorsqu'un changement de DB intra-day se produit (qui se produira 0-2 fois par jour).

J'ai aussi un getter qui retourne un élément sur la carte, et cette méthode s'appelle des centaines de fois par jour.

Je suis inquiet du cas où le getter est appelé Pendant que je vidange et recréer le hashmap, essayez donc de trouver un élément dans une liste vide / malformée. Si je fais ces méthodes synchronisées, il empêche deux lecteurs d'accéder à la getter en même temps, ce qui pourrait être un goulot d'étranglement de la performance. Je ne veux pas prendre trop de succès de performance puisque les écrites se produisent si rarement. Si j'utilise un REENTRANTREADWRITELOCK, cela obligera-t-il une file d'attente sur quiconque appelant le getter jusqu'à ce que le verrouillage est publié? Est-ce que cela permet à plusieurs lecteurs d'accéder à la getter en même temps? Fixera-t-il un seul écrivain à la fois?

codant cela juste une question de ... xxx


0 commentaires

3 Réponses :


2
votes

Oui, si le verrouillage d'écriture est maintenu par un thread, d'autres threads accédant à la méthode Getter bloqueraient car ils ne peuvent pas acquérir le verrou de lecture. Donc tu vas bien ici. Pour plus de détails, veuillez lire le Javadoc de reentrantreadwritelock - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/reentrantreadwritelock.html


0 commentaires

0
votes

Vous donnez un coup de pied à ce moment-là au début de la journée ... vous le mettez à jour 0 à 2 fois par jour et vous le lisez 100 fois par jour. En supposant que la lecture va prendre, disons 1 seconde complète (heure de loonnnng) en une journée de 8 heures (28800 secondes), vous avez toujours une charge de lecture très faible. En regardant les docs pour RetranTreadwritelock, vous pouvez "Tweek" "Tweek", de sorte qu'il sera "juste", ce qui signifie que le fil qui attendait la plus longue obtiendra la serrure. Donc, si vous le souhaitez être juste, je ne pense pas que vos fils d'écriture vont être affamés.

Références

ReentrantreadwreeLock


1 commentaires

Est-ce que le code que j'ai inclus accomplit le scénario de lecteur multiple que j'ai décrit? Je veux seulement empêcher les lecteurs de lire s'il s'agit d'une écriture actuelle. Il y a des centaines de lectures par jour, mais à un moment donné, elles peuvent venir en grappes et faire 20-30 appels à mon getter.



15
votes

Une autre façon d'atteindre cet objectif (sans utiliser de verrous) est le motif de copie-écriture. Cela fonctionne bien lorsque vous n'écrivez pas souvent. L'idée est de copier et de remplacer le champ lui-même. Il peut ressembler à ce qui suit: xxx

avec ceci, les lecteurs sont entièrement simultanés et la seule pénalité qu'ils paient sont une lecture volatile sur mystuffe_ (qui est très peu). Les écrivains sont synchronisés pour assurer l'exclusion mutuelle.


6 commentaires

Excellente réponse. Notez que si vous savez qu'il n'y a qu'un seul écrivain, vous n'avez pas besoin de synchroniser Setter () . En outre, si vous accédez à une ancienne carte n'est pas un problème, vous n'auriez pas besoin de volatile , car les accès aux références sont toujours atomiques (mais vous pouvez utiliser l'ancienne carte pendant une longue période).


S'il n'y a qu'un seul écrivain, la synchronisation peut être ignorée. Cependant, vous avez toujours besoin de volatils, car il établit qu'il se passe auparavant. Sans volatile, vous souffririez de problèmes de réorganisation.


C'est pourquoi j'ai dit: "Si l'accès à une ancienne carte n'est pas un problème", et "vous pouvez utiliser l'ancienne carte pendant une longue période" :) :)


Avoir une référence fade est une conséquence, mais la réorganisation peut causer des problèmes plus graves. Un autre thread peut voir la nouvelle référence (mystuff_) avant que l'opération de régression soit terminée en raison de la réorganisation.


Ah, oui, j'ai raté celui-là. Donc volatile est vraiment nécessaire.


Aucun effet secondaire d'une action atomique n'est visible jusqu'à ce que l'action soit complète. Et lire et écrit sont atomiques pour toutes les variables déclarées volatiles.So Utilisation volatile, peut rendre mysty_ = copier atomique, et lorsque Call Getter (String A) est en cours d'exécution MYSTUFF_ = Copier, getter (String A) bloquera jusqu'à ce que mystuff_ = copie ait terminé