1. 程式人生 > 程式設計 >Java記憶體快取工具Guava LoadingCache使用解析

Java記憶體快取工具Guava LoadingCache使用解析

這篇文章主要介紹了Java記憶體快取工具Guava LoadingCache使用解析,文中通過示例程式碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

一、Guava介紹

Guava是Google guava中的一個記憶體快取模組,用於將資料快取到JVM記憶體中。實際專案開發中經常將一些公共或者常用的資料快取起來方便快速訪問。

Guava Cache是單個應用執行時的本地快取。它不把資料存放到檔案或外部伺服器。如果不符合需求,可以選擇Memcached、Redis等工具。

二、程式碼示例

1. POM引入

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>28.1-jre</version>
</dependency>

2. 封裝工具類

package com.soyoung.ad.engine.util;
 
import com.google.common.cache.*;
import lombok.extern.slf4j.Slf4j;
 
import java.util.Map;
import java.util.concurrent.TimeUnit;
 
/**
 * 功能描述
 *
 * @author 馬振全 2020/1/13 16:18
 */
@Slf4j
public class CacheManager {
 
  /** 快取項最大數量 */
  private static final long GUAVA_CACHE_SIZE = 100000;
 
  /** 快取時間:天 */
  private static final long GUAVA_CACHE_DAY = 10;
 
  /** 快取操作物件 */
  private static LoadingCache<Long,String> GLOBAL_CACHE = null;
 
  static {
    try {
      GLOBAL_CACHE = loadCache(new CacheLoader<Long,String>() {
        @Override
        public String load(Long key) throws Exception {
          // 處理快取鍵不存在快取值時的處理邏輯
          return "";
        }
      });
    } catch (Exception e) {
      log.error("初始化Guava Cache出錯",e);
    }
  }
 
  /**
   * 全域性快取設定
   *
   * 快取項最大數量:100000
   * 快取有效時間(天):10
   *
   *
   * @param cacheLoader
   * @return
   * @throws Exception
   */
  private static LoadingCache<Long,String> loadCache(CacheLoader<Long,String> cacheLoader) throws Exception {
    LoadingCache<Long,String> cache = CacheBuilder.newBuilder()
        //快取池大小,在快取項接近該大小時, Guava開始回收舊的快取項
        .maximumSize(GUAVA_CACHE_SIZE)
        //設定時間物件沒有被讀/寫訪問則物件從記憶體中刪除(在另外的執行緒裡面不定期維護)
        .expireAfterAccess(GUAVA_CACHE_DAY,TimeUnit.DAYS)
        // 設定快取在寫入之後 設定時間 後失效
        .expireAfterWrite(GUAVA_CACHE_DAY,TimeUnit.DAYS)
        //移除監聽器,快取項被移除時會觸發
        .removalListener(new RemovalListener<Long,String>() {
          @Override
          public void onRemoval(RemovalNotification<Long,String> rn) {
            //邏輯操作
          }
        })
        //開啟Guava Cache的統計功能
        .recordStats()
        .build(cacheLoader);
    return cache;
  }
 
  /**
   * 設定快取值
   * 注: 若已有該key值,則會先移除(會觸發removalListener移除監聽器),再新增
   *
   * @param key
   * @param value
   */
  public static void put(Long key,String value) {
    try {
      GLOBAL_CACHE.put(key,value);
    } catch (Exception e) {
      log.error("設定快取值出錯",e);
    }
  }
 
  /**
   * 批量設定快取值
   *
   * @param map
   */
  public static void putAll(Map<? extends Long,? extends String> map) {
    try {
      GLOBAL_CACHE.putAll(map);
    } catch (Exception e) {
      log.error("批量設定快取值出錯",e);
    }
  }
 
  /**
   * 獲取快取值
   * 注:如果鍵不存在值,將呼叫CacheLoader的load方法載入新值到該鍵中
   *
   * @param key
   * @return
   */
  public static String get(Long key) {
    String token = "";
    try {
      token = GLOBAL_CACHE.get(key);
    } catch (Exception e) {
      log.error("獲取快取值出錯",e);
    }
    return token;
  }
 
  /**
   * 移除快取
   *
   * @param key
   */
  public static void remove(Long key) {
    try {
      GLOBAL_CACHE.invalidate(key);
    } catch (Exception e) {
      log.error("移除快取出錯",e);
    }
  }
 
  /**
   * 批量移除快取
   *
   * @param keys
   */
  public static void removeAll(Iterable<Long> keys) {
    try {
      GLOBAL_CACHE.invalidateAll(keys);
    } catch (Exception e) {
      log.error("批量移除快取出錯",e);
    }
  }
 
  /**
   * 清空所有快取
   */
  public static void removeAll() {
    try {
      GLOBAL_CACHE.invalidateAll();
    } catch (Exception e) {
      log.error("清空所有快取出錯",e);
    }
  }
 
  /**
   * 獲取快取項數量
   *
   * @return
   */
  public static long size() {
    long size = 0;
    try {
      size = GLOBAL_CACHE.size();
    } catch (Exception e) {
      log.error("獲取快取項數量出錯",e);
    }
    return size;
  }
}

三、使用總結

1. 移除機制

guava做cache時候資料的移除分為被動移除和主動移除兩種。

被動移除分為三種:

基於大小的移除:數量達到指定大小,會把不常用的鍵值移除

基於時間的移除:expireAfterAccess(long,TimeUnit) 根據某個鍵值對最後一次訪問之後多少時間後移除
        expireAfterWrite(long,TimeUnit) 根據某個鍵值對被建立或值被替換後多少時間移除

基於引用的移除:主要是基於java的垃圾回收機制,根據鍵或者值的引用關係決定移除

主動移除分為三種:1).單獨移除:Cache.invalidate(key)

         2).批量移除:Cache.invalidateAll(keys)

         3).移除所有:Cache.invalidateAll()

如果配置了移除監聽器RemovalListener,則在所有移除的動作時會同步執行該listener下的邏輯。

如需改成非同步,使用:RemovalListeners.asynchronous(RemovalListener,Executor)

2. 遇到的問題

在put操作之前,如果已經有該鍵值,會先觸發removalListener移除監聽器,再新增
配置了expireAfterAccess和expireAfterWrite,但在指定時間後沒有被移除。

解決方案:CacheBuilder構建的快取不會在特定時間自動執行清理和回收工作,也不會在某個快取項過期後馬上清理,它不會啟動一個執行緒來進行快取維護,因為a)執行緒相對較重,b)某些環境限制執行緒的建立。它會在寫操作時順帶做少量的維護工作,或者偶爾在讀操作時做。當然,也可以建立自己的維護執行緒,以固定的時間間隔呼叫Cache.cleanUp()。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。