Кэширование в Java: Map с автоудалением по времени

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для создания самоуничтожающейся карты в Java вы можете воспользоваться кэшем Guava, позволяющим удалять элементы после определённого периода времени. В таком случае нам поможет CacheBuilder, автоматически указывающий время жизни каждого ключа:

Java
Скопировать код
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

Cache<String, String> expiringCache = CacheBuilder.newBuilder()
      .expireAfterWrite(10, TimeUnit.MINUTES)
      .build();

expiringCache.put("key", "value"); // Время работы – 10 минут, как время на парковке!

Представленный код создаёт карту, элементы из которой исчезают через 10 минут после добавления. Не забудьте включить Guava в зависимости вашего проекта, чтобы использовать CacheBuilder.

Кинга Идем в IT: пошаговый план для смены профессии

Рассмотрение альтернативных решений

Если же Guava не подходит для ваших задач, существуют альтернативные решения для создания карты с ограничением времени жизни элементов. Однако, для их интегрирования потребуются некоторые компромиссы.

CompletableFuture для очистки

С помощью CompletableFuture можно назначить удаление данных. Хоть это не является по настоящему функционирующим кэшированием, такой подход подойдёт для выполнения простых задач:

Java
Скопировать код
Map<String, Pair<String, CompletableFuture<Void>>> map = new ConcurrentHashMap<>();

map.put("key", Pair.of("value", CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(TimeUnit.MINUTES.toMillis(10));
        map.remove("key");
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}))); // Этот ключ исчезнет быстрее, чем последний кусок пиццы на вечеринке

Такая реализация позволяет запланировать CompletableFuture для удаления ключа после определённого времени. Это решение эффективно, но не является лучшим выбором для масштабируемых задач.

Потоковый планировщик для очистки

Если требуется более глубокий контроль над процессом, можно применить ScheduledExecutorService, который будет постоянно удалять устаревшие элементы:

Java
Скопировать код
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> map.keySet().removeIf(key -> /* логика скорости извлечения */), 
    0, 10, TimeUnit.MINUTES); // Так данные играют свою последнюю ноту!

Этот метод обеспечивает регулярное удаление данных , что особенно актуально, если алгоритм проверки срока удаления не является тривиальным.

Визуализация

Представьте себе парковку, где места предоставляются автомобилям на ограниченный промежуток времени:

Markdown
Скопировать код
🚗 = Автомобиль (Данные)
⏳ = Время до убытия
🅿️ = Парковочное место (Ключ)

Как только время вышло, машина покидает парковку, освобождая место:

Markdown
Скопировать код
Парковка (первоначально):
| 🅿️ 1 | 🅿️ 2 | 🅿️ 3 |
|  🚗⏳ |  🚗⏳ |  🚗⏳ |

Парковка (некоторое время спустя):
| 🅿️ 1     | 🅿️ 2 | 🅿️ 3 |
| (вакантно)|  🚗⏳ |  🚗⏳ |

Аналогичным образом, карта с установленным временем жизни удаляет ключи после окончания их срока действия:

Markdown
Скопировать код
Кэш (в начале):
| Ключ 1 | Ключ 2 | Ключ 3 |
| Знач⏳ | Знач⏳ | Знач⏳ |

Кэш (когда сроки истекают):
| Ключ 1    | Ключ 2 | Ключ 3 |
| (удалено) | Знач⏳ | Знач⏳ |

Ключи, аналогично парковочным местам, освобождаются по истечении заданного времени.

Другие возможности кэширования

В дополнение к Guava, существует большое количество кэш-библиотек, способных удовлетворить ваши потребности. Кратко остановимся на некоторых из них:

WeakConcurrentHashMap на GitHub

Эта карта идеально подходит для эффективного использования памяти. Она автоматически удаляет элементы, которые более не нужны:

Java
Скопировать код
WeakConcurrentHashMap<String, MyObject> map = new WeakConcurrentHashMap<>(timeout, unit);
map.put("key", new MyObject()); // Успешно справляется с очисткой места, как самоочищающийся духовой шкаф

PassiveExpiringMap из Apache Commons

Простое и легковесное решение, однако в ситуации с многопоточностью без дополнительной синхронизации потребуется особая осторожность:

Java
Скопировать код
Map<String, String> expiringMap = new PassiveExpiringMap<>(TimeUnit.MINUTES.toMillis(10));
expiringMap.put("key", "value"); // Срок существования ограничен, как у абонемента в спортзал

Ehcache

Мощное решение с множеством функций для корпоративных приложений, поддерживающее настройку в коде:

Java
Скопировать код
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
cacheManager.init();

Cache<Long, String> myCache = cacheManager.createCache("myCache", 
    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, 
    ResourcePoolsBuilder.heap(100)).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(10))));
// Оснащён большим количеством функций, чем современный смартфон!

Выбирая систему кэширования, следует учитывать такие факторы, как производительность, параллельный доступ, потребление памяти и удобство обслуживания.

Полезные материалы

  1. CacheBuilder (Guava: Google Core Libraries for Java 23.0 API)официальная документация по утилитам кэширования от Guava.
  2. GitHub – ben-manes/caffeine: A high performance caching library for Java — современная и высокопроизводительная библиотека кэширования для Java.
  3. Documentation — официальная документация фреймворка Ehcache для эффективного кэширования в Java.
  4. GitHub – jhalterman/expiringmap: A high performance thread-safe map that expires entries — реализация карты Java с автоматическим истечением срока действия записей.
  5. Reactor 3 Reference Guide — введение в Reactor 3, ключевую библиотеку для реактивного программирования в Java.
  6. The Java Community Process(SM) Program – JSRs: Java Specification Requests – detail JSR# 107 – детали спецификации JCache (JSR-107), стандартные кэширующие аннотации для Java.