java-本地緩存實現


Java-ConcurrentHashMap實現緩存,(緩存數量,過期時間,過期緩存清理)

public class ConcurrentHashMapCacheUtils {
 
    private static Logger LOGGER = LoggerFactory.getLogger(ConcurrentHashMapCacheUtils.class);
 
    /**
     * 緩存最大個數
     */
    private static final Integer CACHE_MAX_NUMBER = 1000;
    /**
     * 當前緩存個數
     */
    private static Integer CURRENT_SIZE = 0;
    /**
     * 時間一分鍾
     */
    static final Long ONE_MINUTE = 60 * 1000L;
    /**
     * 緩存對象
     */
    private static final Map<String, CacheObj> CACHE_OBJECT_MAP = new ConcurrentHashMap<>();
    /**
     * 這個記錄了緩存使用的最后一次的記錄,最近使用的在最前面
     */
    private static final List<String> CACHE_USE_LOG_LIST = new LinkedList<>();
    /**
     * 清理過期緩存是否在運行
     */
    private static volatile Boolean CLEAN_THREAD_IS_RUN = false;
 
 
    /**
     * 設置緩存
     */
    public static void setCache(String cacheKey, Object cacheValue, long cacheTime) {
        Long ttlTime = null;
        if (cacheTime <= 0L) {
            if (cacheTime == -1L) {
                ttlTime = -1L;
            } else {
                return;
            }
        }
        checkSize();
        saveCacheUseLog(cacheKey);
        CURRENT_SIZE = CURRENT_SIZE + 1;
        if (ttlTime == null) {
            ttlTime = System.currentTimeMillis() + cacheTime;
        }
        CacheObj cacheObj = new CacheObj(cacheValue, ttlTime);
        CACHE_OBJECT_MAP.put(cacheKey, cacheObj);
        LOGGER.info("have set key :" + cacheKey);
    }
    /**
     * 設置緩存
     */
    public static void setCache(String cacheKey, Object cacheValue) {
        setCache(cacheKey, cacheValue, -1L);
    }
    /**
     * 獲取緩存
     */
    public static Object getCache(String cacheKey) {
        startCleanThread();
        if (checkCache(cacheKey)) {
            saveCacheUseLog(cacheKey);
            return CACHE_OBJECT_MAP.get(cacheKey).getCacheValue();
        }
        return null;
    }
    public static boolean isExist(String cacheKey) {
        return checkCache(cacheKey);
    }
    /**
     * 刪除所有緩存
     */
    public static void clear() {
        LOGGER.info("have clean all key !");
        CACHE_OBJECT_MAP.clear();
        CURRENT_SIZE = 0;
    }
    /**
     * 刪除某個緩存
     */
    public static void deleteCache(String cacheKey) {
        Object cacheValue = CACHE_OBJECT_MAP.remove(cacheKey);
        if (cacheValue != null) {
            LOGGER.info("have delete key :" + cacheKey);
            CURRENT_SIZE = CURRENT_SIZE - 1;
        }
    }
    /**
     * 判斷緩存在不在,過沒過期
     */
    private static boolean checkCache(String cacheKey) {
        CacheObj cacheObj = CACHE_OBJECT_MAP.get(cacheKey);
        if (cacheObj == null) {
            return false;
        }
        if (cacheObj.getTtlTime() == -1L) {
            return true;
        }
        if (cacheObj.getTtlTime() < System.currentTimeMillis()) {
            deleteCache(cacheKey);
            return false;
        }
        return true;
    }
    /**
     * 刪除最近最久未使用的緩存
     */
    private static void deleteLRU() {
        LOGGER.info("delete Least recently used run!");
        String cacheKey = null;
        synchronized (CACHE_USE_LOG_LIST) {
            if (CACHE_USE_LOG_LIST.size() >= CACHE_MAX_NUMBER - 10) {
                cacheKey = CACHE_USE_LOG_LIST.remove(CACHE_USE_LOG_LIST.size() - 1);
            }
        }
        if (cacheKey != null) {
            deleteCache(cacheKey);
        }
    }
 
    /**
     * 刪除過期的緩存
     */
    static void deleteTimeOut() {
        LOGGER.info("delete time out run!");
        List<String> deleteKeyList = new LinkedList<>();
        for(Map.Entry<String, CacheObj> entry : CACHE_OBJECT_MAP.entrySet()) {
            if (entry.getValue().getTtlTime() < System.currentTimeMillis() && entry.getValue().getTtlTime() != -1L) {
                deleteKeyList.add(entry.getKey());
            }
        }
        for (String deleteKey : deleteKeyList) {
            deleteCache(deleteKey);
        }
        LOGGER.info("delete cache count is :" + deleteKeyList.size());
    }
    /**
     * 檢查大小
     * 當當前大小如果已經達到最大大小
     * 首先刪除過期緩存,如果過期緩存刪除過后還是達到最大緩存數目
     * 刪除最久未使用緩存
     */
    private static void checkSize() {
        if (CURRENT_SIZE >= CACHE_MAX_NUMBER) {
            deleteTimeOut();
        }
        if (CURRENT_SIZE >= CACHE_MAX_NUMBER) {
            deleteLRU();
        }
    }
 
    /**
     * 保存緩存的使用記錄
     */
    private static synchronized void saveCacheUseLog(String cacheKey) {
        synchronized (CACHE_USE_LOG_LIST) {
            CACHE_USE_LOG_LIST.remove(cacheKey);
            CACHE_USE_LOG_LIST.add(0,cacheKey);
        }
    }
 
    /**
     * 設置清理線程的運行狀態為正在運行
     */
    static void setCleanThreadRun() {
        CLEAN_THREAD_IS_RUN = true;
    }
 
    /**
     * 開啟清理過期緩存的線程
     */
    private static void startCleanThread() {
        if (!CLEAN_THREAD_IS_RUN) {
            CleanTimeOutThread cleanTimeOutThread = new CleanTimeOutThread();
            Thread thread = new Thread(cleanTimeOutThread);
            //設置為后台守護線程
            thread.setDaemon(true);
            thread.start();
        }
    }
 
}
 
class CacheObj {
    /**
     * 緩存對象
     */
    private Object CacheValue;
    /**
     * 緩存過期時間
     */
    private Long ttlTime;
 
    CacheObj(Object cacheValue, Long ttlTime) {
        CacheValue = cacheValue;
        this.ttlTime = ttlTime;
    }
 
    Object getCacheValue() {
        return CacheValue;
    }
 
    Long getTtlTime() {
        return ttlTime;
    }
 
    @Override
    public String toString() {
        return "CacheObj {" +
                "CacheValue = " + CacheValue +
                ", ttlTime = " + ttlTime +
                '}';
    }
}
 
/**
 * 每一分鍾清理一次過期緩存
 */
class CleanTimeOutThread implements Runnable{
 
    @Override
    public void run() {
        ConcurrentHashMapCacheUtils.setCleanThreadRun();
        while (true) {
            System.out.println("clean thread run ");
            ConcurrentHashMapCacheUtils.deleteTimeOut();
            try {
                Thread.sleep(ConcurrentHashMapCacheUtils.ONE_MINUTE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 

以上實現略有瑕疵: 容易造成緩存最大數的溢出;

 

參考:https://blog.csdn.net/qq_35030994/article/details/80871279


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM