Quatre techniques pour utiliser HashMap en toute sécurité

Dans cet article, nous parlons de quatre techniques pour utiliser HashMap en toute sécurité.

1 méthode à l'intérieur : utilisez un HashMap séparé par thread

Comme le montre la figure ci-dessous, une fois que Tomcat a reçu la demande, il appelle successivement les méthodes pertinentes du contrôleur, de la couche de service et de la couche d'accès à la base de données.

Chaque fois que la méthode de couche de service serviceMethod est accédée, un HashMap distinct sera créé dans le corps de la méthode, les paramètres de requête pertinents seront copiés dans le HashMap, puis la méthode DAO sera appelée pour effectuer des opérations de base de données.

Chaque thread de traitement HTTP a sa propre instance à l'intérieur du corps de la méthode de la couche de service HashMap. Dans un environnement multithread, HashMapaucune opération de synchronisation n'est nécessaire.

C’est également le moyen le plus courant et le plus sûr que nous utilisons, et c’est l’opération la plus basique de CRUD.

2 Données de configuration : écriture initiale, lecture ultérieure uniquement

Après le démarrage du système, nous pouvons charger les données de configuration dans le cache local HashMap. Une fois les informations de configuration initialisées, il n'est pas nécessaire de les écrire et seules les opérations de lecture sont fournies à l'avenir.

La figure ci-dessus montre une classe de configuration très simple SimpleConfig, qui contient un objet HashMap configMap. Le constructeur appelle la méthode d'initialisation et la logique interne de la méthode d'initialisation consiste à stocker les données de configuration dans un HashMap.

La classe SimpleConfig expose la méthode getConfig au monde extérieur. Une fois que le thread principal a initialisé l'objet SimpleConfig, lorsque d'autres threads appellent la méthode getConfig, celle-ci est thread-safe car il n'y a que des opérations de lecture et aucune opération d'écriture.

3 Verrouillage en lecture-écriture : blocage lors de l'écriture, lecture parallèle, plus de lecture et moins de scénarios d'écriture

Un verrou en lecture-écriture est un verrou divisé en deux parties : un verrou en lecture et un verrou en écriture. Le verrou en lecture permet à plusieurs threads de l'acquérir en même temps, tandis que le verrou en écriture est un verrou d'exclusion mutuelle.

Ses règles sont les suivantes :<strong style="font-size:herit;line-height:herit;color: rgb(255, 104, 39);">La lecture et la lecture ne s'excluent pas mutuellement, la lecture et l'écriture s'excluent mutuellement, et l'écriture et l'écriture s'excluent mutuellement </strong>, adaptées aux scénarios commerciaux avec plus de lecture et moins d'écriture.

Nous utilisons généralement ReentrantReadWriteLock, qui implémente ReadWriteLock. L'interface ReadWriteLock est également très simple. Elle fournit principalement deux méthodes en interne, renvoyant respectivement le verrouillage en lecture et le verrouillage en écriture.

 public interface ReadWriteLock {
    //获取读锁
    Lock readLock();
    //获取写锁
    Lock writeLock();
}

L'utilisation des verrous en lecture-écriture est la suivante :

  1. Créez un objet ReentrantReadWriteLock lors de l'utilisation de ReadWriteLock, il n'est pas utilisé directement, mais obtient son verrou de lecture et son verrou d'écriture internes, puis appelle respectivement la méthode lock/unlock ;
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  1. Lire les données partagées ;
Lock readLock = readWriteLock.readLock();
readLock.lock();
try {
   // TODO 查询共享数据
} finally {
   readLock.unlock();
}
  1. Écrire des données partagées ;
Lock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
   // TODO 修改共享数据
} finally {
   writeLock.unlock();
}

Le code suivant montre comment utiliser ReadWriteLock pour utiliser HashMap en toute sécurité :

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockCache {
  
    // 创建一个 HashMap 来存储缓存的数据
    private Map<String, String> map = new HashMap<>();

    // 创建读写锁对象
    private ReadWriteLock rw = new ReentrantReadWriteLock();

    // 放对象方法:向缓存中添加一个键值对
    public void put(String key, String value) {
        // 获取写锁,以确保当前操作是独占的
        rw.writeLock().lock();
        try {
            // 执行写操作,将键值对放入 map
            map.put(key, value);
        } finally {
            // 释放写锁
            rw.writeLock().unlock();
        }
    }

    // 取对象方法:从缓存中获取一个值
    public String get(String key) {
        // 获取读锁,允许并发读操作
        rw.readLock().lock();
        try {
            // 执行读操作,从 map 中获取值
            return map.get(key);
        } finally {
            // 释放读锁
            rw.readLock().unlock();
        }
    }
}

Utiliser des verrous en lecture-écriture pour faire fonctionner HashMap est une technique très classique. Le middleware de messages RockeMQ NameServer (service de noms) enregistre et interroge les informations de routage via cette technique.

De plus, les verrous en lecture-écriture peuvent exploiter plusieurs HashMap. Par rapport à ConcurrentHashMap, ReadWriteLock peut contrôler la granularité des objets de cache et offre une plus grande flexibilité.

4 Collections.synchronizedMap : verrouillé en lecture et en écriture

Le code suivant, lorsque nous utilisons userMap dans plusieurs threads,

static Map<Long, User> userMap = Collections.synchronizedMap(new HashMap<Long, User>());

Entrez la méthode synchroniséeMap :

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
       return new SynchronizedMap<>(m);
}

SynchronizedMap contient un mutex d'objet de verrouillage d'objet en interne, qui est essentiellement une classe wrapper qui réimplémente les opérations de lecture et d'écriture de HashMap. Nous voyons que chaque fois qu'il est lu ou écrit, le mot-clé synchronisé est utilisé pour assurer la sécurité des threads du. opération.

Bien que la technique Collections.synchronizedMap soit très simple à utiliser, nous devons comprendre qu'elle se verrouillera à chaque lecture et écriture et que les performances ne seront pas particulièrement bonnes.

5 Résumé

Dans cet article, l'auteur résume quatre techniques thread-safe pour utiliser HashMap.

1. À l'intérieur de la méthode : chaque thread utilise un HashMap distinct

C’est la méthode la plus couramment utilisée et la plus fiable. Chaque thread crée une instance à l'intérieur du corps de la méthode HashMap. Dans un environnement multithread, aucune HashMapopération de synchronisation n'est requise.

2. Données de configuration : écriture initiale, lecture ultérieure uniquement

Lorsque le middleware est démarré, il lira le fichier de configuration et écrira les données de configuration dans le HashMap. Une fois l'écriture du thread principal terminée, il n'y aura plus d'opérations d'écriture à l'avenir et d'autres threads pourront le lire, sans provoquer de sécurité des threads. problèmes.

3. Verrouillage en lecture-écriture : blocage lors de l'écriture, lecture parallèle, plus de lecture et moins de scénarios d'écriture.

Un verrou en lecture-écriture est un verrou divisé en deux parties : un verrou en lecture et un verrou en écriture. Le verrou en lecture permet à plusieurs threads de l'acquérir en même temps, tandis que le verrou en écriture est un verrou d'exclusion mutuelle.

Ses règles sont les suivantes :<strong style="font-size:herit;line-height:herit;color: rgb(255, 104, 39);">La lecture et la lecture ne s'excluent pas mutuellement, la lecture et l'écriture s'excluent mutuellement, et l'écriture et l'écriture s'excluent mutuellement </strong>, adaptées aux scénarios commerciaux avec plus de lecture et moins d'écriture.

Utiliser des verrous en lecture-écriture pour faire fonctionner HashMap est une technique très classique. Le middleware de messages RockeMQ NameServer (service de noms) enregistre et interroge les informations de routage via cette technique.

4. Collections.synchronizedMap : verrouillé en lecture et en écriture

La méthode Collections.synchronizedMap utilise le modèle de décorateur pour fournir une classe de décorateur thread-safe SynchronizedMap pour le HashMap non sécurisé pour les threads.

SynchronizedMap est utilisé pour garantir indirectement que le fonctionnement de HashMap est thread-safe, et la couche sous-jacente de SynchronizedMap utilise également le mot-clé synchronisé pour garantir la sécurité des threads des opérations.

Les ressources piratées de "Celebrating More Than Years 2" ont été téléchargées sur npm, obligeant npmmirror à suspendre le service unpkg. L'équipe chinoise d' IA de Microsoft a fait ses valises et s'est rendue aux États-Unis, impliquant des centaines de personnes. La bibliothèque de visualisation frontale et le projet open source bien connu de Baidu, ECharts - "aller à la mer" pour soutenir les escrocs Fish ont utilisé TeamViewer pour transférer 3,98 millions ! Que doivent faire les fournisseurs de postes de travail à distance ? Zhou Hongyi : Il ne reste plus beaucoup de temps à Google. Il est recommandé que tous les produits soient open source. Un ancien employé d'une société open source bien connue a annoncé la nouvelle : après avoir été interpellé par ses subordonnés, le responsable technique est devenu furieux et. a licencié l'employée enceinte. Google a montré comment exécuter ChromeOS sur une machine virtuelle Android. Veuillez me donner quelques conseils, quel rôle joue ici time.sleep(6). Microsoft réagit aux rumeurs selon lesquelles l'équipe chinoise d'IA "fait ses valises pour les États-Unis" Le Quotidien du Peuple commente en ligne la charge de type matriochka des logiciels de bureau : Ce n'est qu'en résolvant activement les "ensembles" que nous pourrons avoir un avenir
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/makemyownlife/blog/11174967
conseillé
Classement