Java Simple nom de la base de serrures?
MySQL dispose d'une fonction très pratique:
SELECT GET_LOCK("SomeName")
Cela peut être utilisé pour créer simple, mais très spécifique, à partir du nom des verrous pour une application. Cependant, elle nécessite une connexion de base de données.
J'ai beaucoup de situations comme:
someMethod() {
//do stuff to user A for their data for feature X
}
Ça n'a pas de sens de simplement synchroniser cette méthode, parce que, par exemple, si cette méthode est appelée pour l'utilisateur B dans l'intervalle, l'utilisateur B n'a pas besoin d'attendre pour Un utilisateur de se terminer avant qu'il ne commence, seules les opérations de l'utilisateur et la fonctionnalité X combinaison besoin d'attendre.
Avec MySql lock je pourrais faire quelque chose comme:
someMethod() {
executeQuery("SELECT GET_LOCK('userA-featureX')")
//only locked for user A for their data for feature X
executeQuery("SELECT RELEASE_LOCK('userA-featureX')")
}
Depuis Java de verrouillage est basé sur des objets, il me semble que j'aurais besoin de créer un nouvel objet à représenter la situation de cette serrure, puis le mettre dans un statique de cache quelque part donc tous les threads peuvent le voir. Des demandes ultérieures de verrouillage pour que la situation serait alors de localiser le verrou de l'objet dans le cache et l'acquisition de son verrouillage. J'ai essayé de créer quelque chose comme ça, mais alors le verrou du cache lui-même a besoin de synchronisation. Aussi, il est difficile de détecter si un verrou de l'objet n'est plus utilisé de sorte qu'il peut être retiré à partir du cache.
J'ai regardé le Java simultanées paquets, mais rien ne se démarque comme étant capable de gérer quelque chose comme ça. Est-il un moyen facile à mettre en œuvre, ou suis-je en regardant ce de la mauvaise perspective?
Edit:
Pour être clair, je ne cherche pas à créer un prédéfini piscine de serrures à l'avance, je voudrais créer sur la demande. Certains pseudo-code pour ce que je pense est:
LockManager.acquireLock(String name) {
Lock lock;
synchronized (map) {
lock = map.get(name);
//doesn't exist yet - create and store
if(lock == null) {
lock = new Lock();
map.put(name, lock);
}
}
lock.lock();
}
LockManager.releaseLock(String name) {
//unlock
//if this was the last hold on the lock, remove it from the cache
}
- Je recommande cette réponse, en utilisant la Goyave est Rayé<Lock> afin d'éviter l'utilisation excessive de mémoire: stackoverflow.com/a/11125602/116810
- Double Possible de la Synchronisation sur les objets String en Java
Vous devez vous connecter pour publier un commentaire.
c'est peut-être utile pour vous: jkeylockmanager
Edit:
Ma première réaction a été sans doute un peu court. Je suis l'auteur et a été confronté à ce problème plusieurs fois et ne pouvait pas trouver une solution existante. C'est pourquoi j'ai fait cette petite bibliothèque sur Google Code.
Toutes ces réponses je vois sont trop compliqués. Pourquoi ne pas simplement utiliser:
Le point clé est la méthode
intern
: il s'assure que la Chaîne de caractères retournée est d'un unique objet, et donc il peut être utilisé en tant que machine virtuelle-exemple à l'échelle de mutex. Tous les internés les Chaînes sont tenues dans un pool mondial, de sorte que votre statique de cache vous parliez dans votre question initiale. Ne vous inquiétez pas à propos de memleaks; ces chaînes seront gc ed si aucun autre thread référence. Notez cependant que, jusqu'à et y compris Java6 cette piscine est gardé dans PermGen space au lieu de le tas, alors vous pourriez avoir à augmenter.Il y a un problème, par contre si un autre code dans votre vm verrous sur la même chaîne pour des raisons complètement différentes, mais une) c'est très peu probable, et b) vous pouvez contourner ce problème en introduisant des espaces de noms, par exemple
executeInNamedLock(this.getClass().getName() + "_" + myLockName);
Interner
Fournit l'équivalent de comportement de laString.intern()
pour d'autres immuable typesPouvez-vous avoir un
Map<String, java.util.concurrent.Lock>
? Chaque fois que vous avez besoin d'une serrure, vous avez essentiellement appelmap.get(lockName).lock()
.Voici un exemple d'utilisation Google Goyave:
Puis
lockMap.get("anyOldString")
sera la cause d'une nouvelle serrure à être créé si nécessaire et est retourné à vous. Vous pouvez ensuite appelerlock()
sur le verrou.makeComputingMap
retourne une Carte qui est thread-safe, vous pouvez simplement partager avec tous vos threads.weakValues()
faire? Si un thread maintenant le verrou se termine (avec ou sans le relâcher), alors il sera GC ed.pool.wait()
fait perdre le fil de la serrure surpool
.Set<String>
avecMap<String, Thread>
et la mise à jour de lawhile
condition.Peut-être un peu plus tard, mais vous pouvez utiliser Google Goyave Rayé
size
paramètre détermine le nombre de cadenas sont gérés sous les couvertures. Rayé attribue des serrures à clés basées sur des codes de hachage. Vous devez définirsize
être proportionnel au nombre d'objets que vous essayez de protéger avec verrouillage. Par exemple, à l'aide desize
=1 pour protéger les 100 objets est le même que le verrouillage exclusif;size
=2 utilisera les 2 verrous de toutes les de 100 objets, si vous avez seulement une chance de 50% de toute la simultanéité à tous; etc. Il peut également être intéressant de se demander combien de fils sont le partage de l'accès lors du calcul de la taille.De verrouillage sur quelque chose comme un nom d'utilisateur, en mémoire
Lock
s dans une carte peut-être un peu baveur. Comme alternative, vous pouvez rechercher à l'aide de WeakReferences avec WeakHashMap pour créer des objets mutex qui peuvent être des ordures collectées lorsque rien n'y fait référence. Cela vous évite de faire n'importe quel manuel de référence de comptage pour libérer de la mémoire.Vous pouvez trouver une mise en œuvre ici. Notez que si vous faites fréquemment des recherches sur la carte, vous risquez de rencontrer les problèmes de conflit d'acquérir le mutex.
finally
bloc. Comme nombre maximum de simultanément serviced les utilisateurs ont tendance à être limité par le nombre de threads actifs. Voir un exemple dans ma réponse: stackoverflow.com/a/24329490/603516Une solution générique à l'aide de java.util.simultanées
Basé sur la réponse de McDowell et de sa classe IdMutexProvider, j'ai écrit à la classe générique
LockMap
qui utilise WeakHashMap pour stocker des objets de verrou.LockMap.get()
peut être utilisé pour récupérer un objet de verrouillage pour une clé, qui peut ensuite être utilisé avec Javasynchronized (...)
déclaration d'appliquer un verrou. Serrure utilisé les objets sont automatiquement libérés lors de la collecte des ordures.Exemple d'utilisation de la LockMap classe:
Un programme de test simple pour le LockMap classe:
Si quelqu'un connaît une meilleure façon de tester automatiquement la LockMap classe, s'il vous plaît écrire un commentaire.
Je tiens à remarquer que
ConcurrentHashMap
a verrouillage intégré installation est assez simple exclusive multithread de verrouillage. Aucune autreLock
objets nécessaires.Voici un exemple de ce type de verrou de la carte utilisée pour appliquer au plus un actif jms de traitement pour un seul client.
2 ans plus tard mais j'ai été la recherche d'un simple nommé casier solution et suis tombé sur ce, a été utile, mais j'avais besoin d'une simple réponse, donc en dessous de ce que je suis venu avec.
Simple de verrouillage sous quelque nom et relâchez à nouveau sous le même nom.
Voici le code:
Peut-être quelque chose comme ça:
Je n'ai pas testé si.
Après une certaine déception qu'il n'existe pas de niveau de langue, de soutien ou de simples Goyave/Commons classe pour nommé les verrous,
C'est ce que je me suis installé à:
Ici que j'ai réalisé: peu de code réutilisable avec aucune dépendance de bibliothèque, de manière atomique de l'acquisition du verrou de l'objet, de ne pas polluer le mondial de l'internement des objets string, pas de bas-niveau de l'informer/attendre le chaos et pas de try-catch-finally mess.
synchronized
bloc qui est plus propre que manuellement appelerlock()
etunlock()
.Similaire à la réponse de Lyomi, mais utilise la plus souple ReentrantLock au lieu d'un bloc synchronisé.
Oui cela va augmenter au fil du temps - mais à l'aide de la ReentrantLock ouvre plus de possibilités de démontage de la serrure de la carte. Bien que, la suppression d'éléments de la carte ne semble pas du tout utile envisage de retirer les valeurs à partir de la carte ne peut pas réduire sa taille. Certains le manuel de la carte de dimensionnement de la logique devrait être mis en œuvre.
Mémoire considération
Souvent, la synchronisation nécessaire pour chaque clé est de courte durée. Garder autour relâché les touches peuvent conduire à des abus de la mémoire des déchets, le rendant non-viable.
Voici une implémentation de ne pas garder en interne autour relâché les touches.
Réentrée, et d'autres cloches et de sifflets
Si l'on veut re-participant de verrouillage de la sémantique, ils peuvent prolonger la ci-dessus en les enveloppant l'objet mutex dans une classe qui conserve la trace de l'verrouillage fil et verrouillé comte.
par exemple:
Si l'on veut
lock()
pour retourner un objet pour en faire des versions plus facile et plus sûr, c'est aussi une possibilité.Mettre tous ensemble, voici de quoi il pourrait ressembler:
Et voici comment on pourrait l'utiliser:
De nombreuses implémentations, mais non semblable à la mienne.
Appelé ma Dynamique de verrouillage de la mise en œuvre
ProcessDynamicKeyLock
parce que c'est un processus unique de verrouillage, pour n'importe quel objet comme clé (ce qui correspond à+hashcode pour l'unicité).TODO: Ajouter un moyen de fournir le verrouillage réelle, par exemple,
ReentrantReadWriteLock
au lieu deReentrantLock
.Mise en œuvre:
Test Simple:
En réponse à la suggestion de l'utilisation des nouvelles Cartographe().makeComputingMap()...
Cartographe().makeComputingMap() est déconseillé pour des raisons de sécurité. Le successeur est CacheBuilder. Avec la faiblesse de clés/valeurs appliquées à CacheBuilder, nous sommes tellement proche d'une solution.
Le problème, c'est une note dans CacheBuilder.weakKeys():
Ce qui rend impossible d'en sélectionner un existant de verrouillage par chaîne de valeur. Erg.
weakValues()
, et pasweakKeys()
? Quand un verrou cesse d'être (fortement) accessible, l'entrée dans le cache devient un candidat pour la suppression de la cache.weakValues()
ne change pas le test d'égalité pour les clés.(4 ans plus tard...)
Ma réponse est similaire à user2878608 mais je pense qu'il manque des cas limites dans cette logique. J'ai aussi pensé Sémaphore était pour le verrouillage de plusieurs ressources à la fois (mais je suppose que de l'utiliser pour le comptage des casiers comme ça, c'est très bien aussi), j'ai donc utilisé un générique POJO verrouillage de l'objet à la place. J'ai couru un test sur elle, qui a démontré chacun de bord il existe des cas de l'OMI et de l'utiliser sur mon projet au travail. Espérons que cela aide quelqu'un. 🙂
J'ai créé un tokenProvider basé sur la IdMutexProvider de McDowell.
Le gestionnaire utilise un
WeakHashMap
qui prend soin de nettoyer inutilisés serrures.TokenManager:
Utilisation:
ou plutôt l'utilisation d'Entiers?
Ce fil est vieux, mais une solution possible est le cadre https://github.com/brandaof/named-lock.
Ici est une simple solution optimisée qui traite de la suppression de utilisé des verrous également, mais avec une surcharge de la synchronisation de la Carte:
}
Votre idée partagée référentiel statique de verrouiller des objets pour chaque situation est correcte.
Vous n'avez pas besoin du cache lui-même pour être synchronisé ... il peut être aussi simple qu'une carte de hachage.
Threads peuvent simultanément obtenir un verrouillage de l'objet à partir de la carte. La réelle logique de synchronisation doit être encapsulé à l'intérieur de chaque objet séparément (voir le java.util.simultanées paquet pour qu' - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/package-summary.html)
TreeMap parce que dans la table de hachage de taille intérieure de la matrice ne peut qu'augmenter