Vier Techniken zur threadsicheren Verwendung von HashMap

In diesem Artikel sprechen wir über vier Techniken zur threadsicheren Verwendung von HashMap.

1 Methode im Inneren: Verwenden Sie eine separate HashMap pro Thread

Wie in der folgenden Abbildung dargestellt, ruft Tomcat nach Erhalt der Anforderung nacheinander die relevanten Methoden des Controllers, der Serviceschicht und der Datenbankzugriffsschicht auf.

Bei jedem Zugriff auf die Service-Layer-Methode serviceMethod wird eine separate HashMap im Methodenkörper erstellt, die relevanten Anforderungsparameter werden in die HashMap kopiert und anschließend wird die DAO-Methode aufgerufen, um Datenbankoperationen auszuführen.

Jeder HTTP-Verarbeitungsthread verfügt über eine eigene Instanz im Methodenkörper der Serviceschicht HashMap. In einer Multithread-Umgebung müssen keine HashMapSynchronisierungsvorgänge durchgeführt werden.

Dies ist auch die gebräuchlichste und sicherste Methode, die wir verwenden, und die grundlegendste Operation von CRUD.

2 Konfigurationsdaten: Erstschreiben, anschließend nur Lesen

Nach dem Systemstart können wir die Konfigurationsdaten in den lokalen Cache HashMap laden. Nachdem die Konfigurationsinformationen initialisiert wurden, müssen sie nicht mehr geschrieben werden, und in Zukunft werden nur Lesevorgänge bereitgestellt.

Die obige Abbildung zeigt eine sehr einfache Konfigurationsklasse SimpleConfig, die ein HashMap-Objekt configMap enthält. Der Konstruktor ruft die Initialisierungsmethode auf, und die interne Logik der Initialisierungsmethode besteht darin, die Konfigurationsdaten in einer HashMap zu speichern.

Die SimpleConfig-Klasse stellt die getConfig-Methode der Außenwelt zur Verfügung. Nachdem der Hauptthread das SimpleConfig-Objekt initialisiert hat, ist es threadsicher, wenn andere Threads die getConfig-Methode aufrufen, da nur Lese- und keine Schreibvorgänge ausgeführt werden.

3 Lese-/Schreibsperre: Blockierung beim Schreiben, paralleles Lesen, mehr Lese- und weniger Schreibszenarien

Eine Lese-/Schreibsperre ist eine Sperre, die in zwei Teile unterteilt ist: eine Lesesperre und eine Schreibsperre. Die Lesesperre ermöglicht es mehreren Threads, sie gleichzeitig zu erwerben, während die Schreibsperre eine gegenseitige Ausschlusssperre ist.

Seine Regeln sind:<strong style="font-size: inherit;line-height: inherit;color: rgb(255, 104, 39);">Lesen und Lesen schließen sich nicht gegenseitig aus, Lesen und Schreiben schließen sich gegenseitig aus und Schreiben und Schreiben schließen sich gegenseitig aus </strong>, geeignet für Geschäftsszenarien mit mehr Lesen und weniger Schreiben.

Wir verwenden im Allgemeinen ReentrantReadWriteLock, das ReadWriteLock implementiert. Die ReadWriteLock-Schnittstelle ist ebenfalls sehr einfach. Sie bietet intern hauptsächlich zwei Methoden: die Rückgabe einer Lesesperre bzw. einer Schreibsperre.

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

Die Verwendung von Lese-/Schreibsperren ist wie folgt:

  1. Erstellen Sie ein ReentrantReadWriteLock-Objekt, das nicht direkt verwendet wird, sondern seine interne Lesesperre und Schreibsperre erhält und dann die Sperr-/Entsperrmethode aufruft.
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  1. Gemeinsame Daten lesen;
Lock readLock = readWriteLock.readLock();
readLock.lock();
try {
   // TODO 查询共享数据
} finally {
   readLock.unlock();
}
  1. Gemeinsame Daten schreiben;
Lock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
   // TODO 修改共享数据
} finally {
   writeLock.unlock();
}

Der folgende Code zeigt, wie Sie ReadWriteLock verwenden, um HashMap threadsicher zu verwenden:

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();
        }
    }
}

Die Verwendung von Lese-/Schreibsperren zum Betreiben von HashMap ist eine sehr klassische Technik. Die Nachrichten-Middleware RockeMQ NameServer (Namensdienst) speichert und fragt Routing-Informationen über diese Technik ab.

Darüber hinaus können Lese-/Schreibsperren mehrere HashMap betreiben. Im Vergleich zu ConcurrentHashMap kann ReadWriteLock die Granularität von Cache-Objekten steuern und bietet eine größere Flexibilität.

4 Collections.synchronizedMap: Sowohl zum Lesen als auch zum Schreiben gesperrt

Der folgende Code, wenn wir userMap in mehreren Threads verwenden,

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

Geben Sie die synchronisierteMap-Methode ein:

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

SynchronizedMap enthält intern einen Objektsperren-Objektmutex, bei dem es sich im Wesentlichen um eine Wrapper-Klasse handelt, die die Lese- und Schreibvorgänge von HashMap neu implementiert. Wir sehen, dass bei jedem Lesen oder Schreiben das synchronisierte Schlüsselwort verwendet wird, um die Thread-Sicherheit sicherzustellen Betrieb.

Obwohl die Collections.synchronizedMap-Technik sehr einfach zu verwenden ist, müssen wir verstehen, dass sie bei jedem Lesen und Schreiben gesperrt wird und die Leistung nicht besonders gut ist.

5 Zusammenfassung

In diesem Artikel fasst der Autor vier threadsichere Techniken zur Verwendung von HashMap zusammen.

1. Innerhalb der Methode: Jeder Thread verwendet eine separate HashMap

Dies ist die am häufigsten verwendete und sehr zuverlässige Methode. Jeder Thread erstellt eine Instanz innerhalb des Methodenkörpers HashMap. In einer Multithread-Umgebung HashMapsind keine Synchronisierungsvorgänge erforderlich.

2. Konfigurationsdaten: Erstschreiben, nachfolgendes Lesen nur

Wenn die Middleware gestartet wird, liest sie die Konfigurationsdatei und schreibt die Konfigurationsdaten in die HashMap. Nachdem der Hauptthread mit dem Schreiben fertig ist, werden in Zukunft keine Schreibvorgänge mehr durchgeführt, und andere Threads können sie lesen, ohne die Thread-Sicherheit zu beeinträchtigen Probleme.

3. Lese-/Schreibsperre: Blockierung beim Schreiben, paralleles Lesen, mehr Lese- und weniger Schreibszenarien

Eine Lese-/Schreibsperre ist eine Sperre, die in zwei Teile unterteilt ist: eine Lesesperre und eine Schreibsperre. Die Lesesperre ermöglicht es mehreren Threads, sie gleichzeitig zu erwerben, während die Schreibsperre eine gegenseitige Ausschlusssperre ist.

Seine Regeln sind:<strong style="font-size: inherit;line-height: inherit;color: rgb(255, 104, 39);">Lesen und Lesen schließen sich nicht gegenseitig aus, Lesen und Schreiben schließen sich gegenseitig aus und Schreiben und Schreiben schließen sich gegenseitig aus </strong>, geeignet für Geschäftsszenarien mit mehr Lesen und weniger Schreiben.

Die Verwendung von Lese-/Schreibsperren zum Betreiben von HashMap ist eine sehr klassische Technik. Die Nachrichten-Middleware RockeMQ NameServer (Namensdienst) speichert und fragt Routing-Informationen über diese Technik ab.

4. Collections.synchronizedMap: Sowohl zum Lesen als auch zum Schreiben gesperrt

Die Collections.synchronizedMap-Methode verwendet das Dekoratormuster , um eine threadsichere Dekoratorklasse SynchronizedMap für die threadunsichere HashMap bereitzustellen.

SynchronizedMap wird verwendet, um indirekt sicherzustellen, dass der Betrieb von HashMap threadsicher ist, und die zugrunde liegende Schicht von SynchronizedMap verwendet auch das synchronisierte Schlüsselwort, um die Thread-Sicherheit des Betriebs sicherzustellen.

Die Raubkopien von „Celebrating More Than Years 2“ wurden auf npm hochgeladen, was dazu führte, dass npmmirror den Unpkg-Dienst einstellen musste und sich gemeinsam mit Hunderten von Menschen in die USA begab Front-End-Visualisierungsbibliothek und Baidus bekanntes Open-Source-Projekt ECharts – „Going to the Sea“ zur Unterstützung Fischbetrüger nutzten TeamViewer, um 3,98 Millionen zu überweisen! Was sollten Remote-Desktop-Anbieter tun? Zhou Hongyi: Für Google bleibt nicht mehr viel Zeit. Es wird empfohlen, dass alle Produkte Open Source sind. Ein ehemaliger Mitarbeiter eines bekannten Open-Source-Unternehmens brachte die Nachricht: Nachdem er von seinen Untergebenen herausgefordert wurde, wurde der technische Leiter wütend hat die schwangere Mitarbeiterin entlassen. Google hat gezeigt, wie man ChromeOS in einer virtuellen Android-Maschine ausführt. Bitte geben Sie mir einen Rat, welche Rolle time.sleep(6) hier spielt. Microsoft reagiert auf Gerüchte, dass Chinas KI-Team „für die USA packt“. People's Daily Online kommentiert die matroschkaartige Aufladung von Bürosoftware: Nur durch das aktive Lösen von „Sets“ können wir eine Zukunft haben
{{o.name}}
{{m.name}}

Ich denke du magst

Origin my.oschina.net/makemyownlife/blog/11174967
Empfohlen
Rangfolge