Cet article présente principalement trois types d'exemples de codes d'implémentation pour les verrous à haute concurrence en Java. L'éditeur pense que c'est assez bon, je vais donc le partager avec vous maintenant et le donner comme référence. Suivons l'éditeur et jetons un coup d'œil
Compétences de base - Verrouillage optimiste
Le verrouillage optimiste convient à de tels scénarios : il n'y aura pas de conflits en lecture mais il y en aura conflits par écrit. La fréquence des lectures simultanées est bien supérieure à celle des écritures.
Prenons comme exemple le code suivant, la mise en œuvre du verrouillage pessimiste :
public Object get(Object key) { synchronized(map) { if(map.get(key) == null) { // set some values } return map.get(key); } }
La mise en œuvre du verrouillage optimiste :
public Object get(Object key) { Object val = null; if((val = map.get(key) == null) { // 当map取值为null时再加锁判断 synchronized(map) { if(val = map.get(key) == null) { // set some value to map... } } } return map.get(key); }
Compétence intermédiaire - String.intern()
Le verrouillage optimiste ne peut pas très bien résoudre un grand nombre de conflits d'écriture, mais dans de nombreux scénarios, le verrou est en fait uniquement destiné à un certain utilisateur ou à une commande. Par exemple, un utilisateur doit d'abord créer une session avant d'effectuer les opérations suivantes. Cependant, pour des raisons de réseau, la demande de création d'une session utilisateur et les demandes ultérieures arrivent presque en même temps, et les threads parallèles peuvent traiter les demandes ultérieures en premier. En général, la sessionMap utilisateur doit être verrouillée, comme le verrou optimiste ci-dessus. Dans ce scénario, le verrouillage peut être limité à l'utilisateur lui-même, c'est-à-dire que l'original
lock.lock(); int num=storage.get(key); storage.set(key,num+1); lock.unlock();
est remplacé par :
lock.lock(key); int num=storage.get(key); storage.set(key,num+1); lock.unlock(key);
Ceci est similaire au concept de verrouillage de table de base de données et de verrouillage de ligne. De toute évidence, la capacité de concurrence du verrouillage de ligne est bien supérieure à celle du verrouillage de table.
L'utilisation de String.inter() est une implémentation concrète de cette idée. La classe String gère un pool de chaînes. Lorsque la méthode interne est appelée, si le pool contient déjà une chaîne égale à cet objet String (tel que déterminé par la méthode equals(Object)), la chaîne du pool est renvoyée. On peut voir que lorsque les chaînes sont identiques, String.intern() renvoie toujours le même objet, ce qui permet de verrouiller le même utilisateur. Étant donné que la granularité du verrouillage est limitée à des utilisateurs spécifiques, le système atteint une concurrence maximale.
public void doSomeThing(String uid) { synchronized(uid.intern()) { // ... } }
CopyOnWriteMap ?
Maintenant que nous parlons d'"un concept similaire aux verrous de ligne dans une base de données", nous devons mentionner MVCC La classe CopyOnWrite en Java implémente MVCC. Copy On Write est un tel mécanisme. Lorsque nous lisons des données partagées, nous les lisons directement sans synchronisation. Lorsque nous modifions les données, nous copions une copie des données actuelles, puis la modifions sur cette copie, une fois terminée, nous utilisons la copie modifiée pour remplacer les données originales. Cette méthode est appelée Copie à l'écriture.
Cependant,,, JDK ne fournit pas CopyOnWriteMap, pourquoi ? Il y a une bonne réponse ci-dessous, c'est-à-dire que nous avons déjà ConcurrentHashMap, pourquoi avons-nous besoin de CopyOnWriteMap ?
Fredrik Bromee a écrit
Je suppose que cela dépend de votre cas d'utilisation, mais pourquoi auriez-vous besoin d'un CopyOnWriteMap alors que vous avez déjà un ConcurrentHashMap ?
Pour une table de recherche simple avec de nombreux lecteurs et seulement une ou quelques mises à jour, c'est un bon choix.
Par rapport à une copie sur une collection en écriture :
Concurrence de lecture :
Égal à une copie sur une collection en écriture . Plusieurs lecteurs peuvent récupérer des éléments de la carte simultanément sans verrouillage.
Concurrence d'écriture :
Meilleure concurrence que la copie sur les collections d'écriture qui sérialisent essentiellement les mises à jour (une mise à jour à la fois). ). En utilisant une carte de hachage simultanée, vous avez de bonnes chances d'effectuer plusieurs mises à jour simultanément si vos clés de hachage sont uniformément réparties.
Si vous souhaitez avoir l'effet d'une copie sur la carte d'écriture, vous pouvez toujours. initialiser un ConcurrentHashMap avec un niveau de concurrence de 1.
Conseils avancés - Le défaut de la classe ConcurrentHashMap
String.inter() est que la maintenance d'un pool de chaînes est placée dans Dans la zone d'autorisation de la JVM, si le nombre d'utilisateurs est particulièrement important, la chaîne placée dans le pool de chaînes sera incontrôlable, ce qui peut entraîner des erreurs de MOO ou un GC complet excessif. Comment pouvons-nous contrôler le nombre de verrous et réduire la granularité des verrous en même temps ? Utiliser Java ConcurrentHashMap directement ? Ou souhaitez-vous ajouter votre propre contrôle plus granulaire ? Ensuite, vous pouvez apprendre de ConcurrentHashMap, diviser les objets qui doivent être verrouillés dans plusieurs compartiments et ajouter un verrou à chaque compartiment. Le pseudo-code est le suivant :
Map locks = new Map(); List lockKeys = new List(); for(int number : 1 - 10000) { Object lockKey = new Object(); lockKeys.add(lockKey); locks.put(lockKey, new Object()); } public void doSomeThing(String uid) { Object lockKey = lockKeys.get(uid.hash() % lockKeys.size()); Object lock = locks.get(lockKey); synchronized(lock) { // do something } }.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!