Използване на MapMaker на Guava

1. Въведение

MapMaker е клас на строител в Гуава, който улеснява създаването на безопасни за нишки карти.

Java вече поддържа WeakHashMap, за да използва слаби референции за ключовете. Но няма готово решение да се използва същото за стойностите. За щастие MapMaker предлага прости методи за изграждане, за да използва WeakReference както за ключовете, така и за стойностите .

В този урок нека видим как MapMaker улеснява създаването на множество карти и използването на слаби препратки.

2. Зависимост на Maven

На първо място, нека добавим зависимостта на Google Guava, която се предлага в Maven Central:

 com.google.guava guava 29.0-jre 

3. Пример за кеширане

Нека разгледаме прост сценарий на сървър, поддържащ няколко кеша за потребителите: кеш на сесия и кеш на профил.

Кешът на сесията е краткотраен, като записите му стават невалидни, след като потребителят вече не е активен. Така че кешът може да премахне записа за потребителя, след като обектът на потребителя се събира.

Кешът на профила обаче може да има по-голямо време за живот (TTL). Записите в кеша на профила стават невалидни само когато потребителят актуализира своя профил.

В този случай кешът може да премахне записа само когато обектът на профила е събран от боклук.

3.1. Структури на данни

Нека създадем класове, които да представят тези обекти.

Ще започнем първо с потребителя:

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

След това сесията:

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

И накрая профилът:

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. Създаване на кешове

Нека създадем екземпляр на ConcurrentMap за кеша на сесията, използвайки метода makeMap :

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

Върнатата карта не позволява нулеви стойности както за ключа, така и за стойността.

Сега нека създадем друг екземпляр на ConcurrentMap за кеша на профила:

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

Забележете, че не сме посочили първоначалния капацитет за кешовете. И така, MapMaker създава карта с капацитет 16 по подразбиране.

Ако искаме, можем да модифицираме капацитета, използвайки метода InitialCapacity :

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

3.3. Промяна на нивото на паралелност

MapMaker задава стойността по подразбиране за нивото на паралелност на 4 . Обаче sessionCache трябва да поддържа по-голям брой едновременни актуализации без никакви спорове за нишки.

Тук на помощ идва методът на concurrencyLevel builder:

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

3.4. Използване на слаби референции

Картите, които създадохме по-горе, използват силни препратки както за ключовете, така и за стойностите. Така че записите остават в картата, дори ако ключовете и стойностите са събрани от боклука. Вместо това трябва да използваме слаби препратки.

А sessionCache влизане е невалиден, след като ключът (потребителския обект) е боклучаря. Така че, нека използваме слаби препратки за ключовете:

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

За profileCache можем да използваме слаби препратки за стойностите:

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

Когато тези препратки се събират на боклук, Guava гарантира, че тези записи няма да бъдат включени в нито една от последващите операции за четене или запис на картата . Въпреки това, размер () метод, понякога може да е в противоречие и може да включва тези записи .

4. Вътрешни елементи на MapMaker

MapMaker създава ConcurrentHashMap по подразбиране, ако слабите препратки не са активирани . Проверките за равенство се извършват по обичайния метод за равностойност.

Ако активираме слаби препратки, MapMaker създава персонализирана карта, представена от набор от хеш таблици вътрешно. Той също така споделя подобни характеристики на производителност като ConcurrentHashMap .

Важна разлика с WeakHashMap обаче е, че проверките за равенство се извършват чрез сравнения на идентичността (== и identityHashCode ).

5. Заключение

В тази кратка статия научихме как да използваме класа MapMaker за създаване на карта, безопасна за нишки. Видяхме и как да персонализираме картата, за да използваме слаби препратки.

Както винаги, пълният изходен код на статията е достъпен в GitHub.