Статьи

Google Guava Cache

Этот пост является продолжением моей серии о Google Guava, на этот раз посвященной кешу Guava. Guava Cache предлагает большую гибкость и мощность, чем HashMap или ConcurrentHashMap, но не такой тяжелый, как использование EHCache или Memcached (или в этом отношении надежный, поскольку Guava Cache работает исключительно в памяти). Интерфейс Cache имеет методы, которые вы ожидаете увидеть как «get» и «invalidate». Метод, который вы не найдете, это «положить», потому что Guava Cache является «самонаполняющимся», значения, которые отсутствуют при запросе, выбираются или вычисляются, а затем сохраняются. Это означает, что вызов get никогда не вернет значение null. Справедливости ради, предыдущее утверждение не является точным на 100%. Есть еще один метод «asMap», который представляет записи в кеше как потокобезопасную карту. Использование asMap приведет к тому, что ни одна из операций самозагрузки не будет выполнена, поэтому вызовы get возвращают значение NULL, если значение отсутствует (что это интересно?). Хотя это пост о Guava Cache, я собираюсь посвятить большую часть времени обсуждению CacheLoader и CacheBuilder. CacheLoader определяет, как загружать значения, а CacheBuilder используется для установки желаемых функций и создания кеша.

CacheLoader

CacheLoader – это абстрактный класс, который определяет, как вычислять или загружать значения, если они отсутствуют. Есть два способа создать экземпляр CacheLoader:

  1. Расширить класс CacheLoader <K, V>
  2. Используйте статический метод фабрики CacheLoader.from

Если вы расширяете CacheLoader, вам нужно переопределить метод V load(K key) , указав, как сгенерировать значение для данного ключа. Используя статический метод CacheLoader.from вы создаете CacheLoader, предоставляя интерфейс Function или Supplier. При предоставлении объекта Function функция применяется к ключу для вычисления или получения результатов. Используя интерфейс поставщика, значение получается независимо от ключа.

CacheBuilder

CacheBuilder используется для создания экземпляров кэша. Он использует свободный стиль сборки и дает вам возможность установить следующие свойства в кеше:

  • Ограничение размера кэша (при удалении используется алгоритм LRU)
  • Обертывание ключей в WeakReferences (Сильные ссылки используются по умолчанию для ключей)
  • Обтекание значений в WeakReferences или SoftReferences (по умолчанию используются сильные ссылки)
  • Время истекает после последнего доступа
  • Время окончания срока действия записей после написания или обновления
  • Установка RemovalListener, который может получать события после удаления записи из кэша
  • Уровень параллелизма кэша (по умолчанию 4)

Параметр уровня параллелизма используется для внутреннего разделения таблицы, чтобы обновления могли происходить без конфликтов. Идеальным параметром будет максимальное количество потоков, которые могут потенциально получить доступ к кэшу за один раз. Вот пример возможного сценария использования Guava Cache.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class PersonSearchServiceImpl implements SearchService<List<Person>> {
 
public PersonSearchServiceImpl(SampleLuceneSearcher luceneSearcher, SampleDBService dbService) {
        this.luceneSearcher = luceneSearcher;
        this.dbService = dbService;
        buildCache();
    }
 
    @Override
    public List<Person> search(String query) throws Exception {
        return cache.get(query);
    }
 
    private void buildCache() {
        cache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(1000)
                .build(new CacheLoader<String, List<Person>>() {
                    @Override
                    public List<Person> load(String queryKey) throws Exception {
                        List<String> ids = luceneSearcher.search(queryKey);
                        return dbService.getPersonsById(ids);
                    }
                });
    }
}

В этом примере я устанавливаю срок действия записей кэша через 10 минут после записи или обновления в кэше с максимальным объемом 1000 записей. Обратите внимание на использование CacheLoader в строке 15.

RemovalListener

RemovalListener получит уведомление об удалении элемента из кэша. Эти уведомления могут быть получены вручную или автоматически из-за истечения времени или сбора мусора. Параметры RemovalListener <K, V> могут быть установлены для прослушивания определенного типа. Чтобы получать уведомления о любом ключе или значении, установите их для использования объекта. Здесь следует отметить, что RemovalListener получит объект RemovalNotification <K, V>, который реализует интерфейс Map.Entry. Ключ или значение могут быть нулевыми, если один из них уже был собран мусором. Также ключ и значение объекта будут сильными ссылками, независимо от типа ссылок, используемых кешем.

CacheStats

Существует также очень полезный класс CacheStats, который можно получить с помощью вызова Cache.stats (). Объект CacheStats может дать
понимание эффективности и производительности вашего кэша, предоставляя такие статистические данные, как:

  • счетчик посещений
  • промах
  • общая нагрузка
  • Всего запросов

CacheStats предоставляет много других подсчетов в дополнение к перечисленным выше.

Вывод

Кеш Guava представляет собой очень привлекательную функциональность Решение использовать Guava Cache действительно сводится к компромиссу между доступностью / использованием памяти и увеличением производительности. Я добавил модульный тест CacheTest, демонстрирующий использование, обсуждаемое здесь. Как всегда комментарии и предложения приветствуются. Спасибо за ваше время.

Ресурсы

Ссылка: Google Guava Cache от нашего партнера по JCG Билла Бекака в блоге « Случайные мысли о кодировании» .