Verwenden von Guavas MapMaker

1. Einleitung

MapMaker ist eine Builder-Klasse in Guava, die das Erstellen threadsicherer Karten erleichtert.

Java unterstützt WeakHashMap bereits , um schwache Referenzen für die Schlüssel zu verwenden. Es gibt jedoch keine sofort einsatzbereite Lösung, um diese für die Werte zu verwenden. Glücklicherweise bietet MapMaker einfache Builder-Methoden, um WeakReference sowohl für die Schlüssel als auch für die Werte zu verwenden .

In diesem Tutorial sehen wir uns an, wie MapMaker das Erstellen mehrerer Karten und das Verwenden schwacher Referenzen vereinfacht.

2. Maven-Abhängigkeit

Fügen wir zunächst die Google Guava-Abhängigkeit hinzu, die in Maven Central verfügbar ist:

 com.google.guava guava 29.0-jre 

3. Ein Caching-Beispiel

Betrachten wir ein einfaches Szenario, in dem ein Server einige Caches für die Benutzer verwaltet: einen Sitzungscache und einen Profilcache.

Der Sitzungscache ist von kurzer Dauer und seine Einträge werden ungültig, nachdem der Benutzer nicht mehr aktiv ist. So kann der Cache den Eintrag für den Benutzer entfernen, nachdem das Benutzerobjekt durch Müll gesammelt wurde.

Der Profilcache kann jedoch eine höhere Lebensdauer (TTL) haben. Die Einträge im Profilcache werden erst ungültig, wenn der Benutzer sein Profil aktualisiert.

In diesem Fall kann der Cache den Eintrag nur entfernen, wenn das Profilobjekt durch Müll gesammelt wurde.

3.1. Datenstrukturen

Erstellen wir Klassen, um diese Entitäten darzustellen.

Wir beginnen zuerst mit dem Benutzer:

public class User { private long id; private String name; public User(long id, String name) { this.id = id; this.name = name; } public long getId() { return id; } public String getName() { return name; } }

Dann die Sitzung:

public class Session { private long id; public Session(long id) { this.id = id; } public long getId() { return id; } } 

Und zum Schluss das Profil:

public class Profile { private long id; private String type; public Profile(long id, String type) { this.id = id; this.type = type; } public long getId() { return id; } public String getName() { return type; } }

3.2. Caches erstellen

Erstellen wir eine Instanz von ConcurrentMap für den Sitzungscache mit der Methode makeMap :

ConcurrentMap sessionCache = new MapMaker().makeMap();

Die zurückgegebene Zuordnung erlaubt keine Nullwerte sowohl für den Schlüssel als auch für den Wert.

Jetzt erstellen wir eine weitere Instanz von ConcurrentMap für den Profilcache:

ConcurrentMap profileCache = new MapMaker().makeMap();

Beachten Sie, dass wir die anfängliche Kapazität für die Caches nicht angegeben haben. Daher erstellt MapMaker standardmäßig eine Karte mit einer Kapazität von 16.

Wenn wir möchten, können wir die Kapazität mit der initialCapacity- Methode ändern :

ConcurrentMap profileCache = new MapMaker().initialCapacity(100).makeMap();

3.3. Ändern der Parallelitätsstufe

MapMaker setzt den Standardwert für die Parallelitätsstufe auf 4 . Der sessionCache muss jedoch eine höhere Anzahl gleichzeitiger Updates ohne Thread-Konflikte unterstützen.

Hier hilft die Builder-Methode concurrencyLevel :

ConcurrentMap sessionCache = new MapMaker().concurrencyLevel(10).makeMap();

3.4. Schwache Referenzen verwenden

Die oben erstellten Karten verwenden starke Referenzen sowohl für die Schlüssel als auch für die Werte. Die Einträge bleiben also auch dann in der Karte, wenn die Schlüssel und Werte durch Müll gesammelt werden. Wir sollten stattdessen schwache Referenzen verwenden.

Ein sessionCache- Eintrag ist ungültig, nachdem der Schlüssel (das Benutzerobjekt) durch Müll gesammelt wurde. Verwenden wir also schwache Referenzen für die Schlüssel:

ConcurrentMap sessionCache = new MapMaker().weakKeys().makeMap();

Für den profileCache können wir schwache Referenzen für die Werte verwenden:

ConcurrentMap profileCache = new MapMaker().weakValues().makeMap();

Wenn diese Referenzen durch Müll gesammelt werden, garantiert Guava, dass diese Einträge in keinem der nachfolgenden Lese- oder Schreibvorgänge auf der Karte enthalten sind . Die size () -Methode kann jedoch manchmal inkonsistent sein und diese Einträge enthalten .

4. MapMaker Internals

MapMaker erstellt standardmäßig eine ConcurrentHashMap, wenn schwache Referenzen nicht aktiviert sind . Die Gleichheitsprüfungen erfolgen nach der üblichen Gleichheitsmethode.

Wenn wir schwache Referenzen aktivieren, erstellt MapMaker eine benutzerdefinierte Map, die intern durch eine Reihe von Hash-Tabellen dargestellt wird. Es weist auch ähnliche Leistungsmerkmale wie eine ConcurrentHashMap auf .

Ein wichtiger Unterschied zu WeakHashMap besteht jedoch darin, dass die Gleichheitsprüfungen über die Vergleiche der Identität (== und identityHashCode ) erfolgen.

5. Schlussfolgerung

In diesem kurzen Artikel haben wir gelernt, wie Sie mit der MapMaker- Klasse eine thread-sichere Map erstellen. Wir haben auch gesehen, wie die Karte so angepasst werden kann, dass schwache Referenzen verwendet werden.

Wie immer ist der vollständige Quellcode des Artikels auf GitHub verfügbar.