這篇文章給大家分享的是有關基于LoadingCache實現(xiàn)Java本地緩存的方法的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
創(chuàng)新互聯(lián)主要從事成都做網(wǎng)站、網(wǎng)站設計、外貿(mào)營銷網(wǎng)站建設、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務神農(nóng)架林區(qū),十余年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:13518219792
Java的特點有哪些 1.Java語言作為靜態(tài)面向?qū)ο缶幊陶Z言的代表,實現(xiàn)了面向?qū)ο罄碚?,允許程序員以優(yōu)雅的思維方式進行復雜的編程。 2.Java具有簡單性、面向?qū)ο?、分布式、安全性、平臺獨立與可移植性、動態(tài)性等特點。 3.使用Java可以編寫桌面應用程序、Web應用程序、分布式系統(tǒng)和嵌入式系統(tǒng)應用程序等。
前言
Guava是Google開源出來的一套工具庫。其中提供的cache模塊非常方便,是一種與ConcurrentMap相似的緩存Map。
開始構建
一. 添加依賴
com.google.guava guava 27.1-jre
二.創(chuàng)建 CacheLoader
LoadingCachecache = CacheBuilder.newBuilder() //緩存池大小,在緩存項接近該大小時, Guava開始回收舊的緩存項 .maximumSize(GUAVA_CACHE_SIZE) //設置時間對象沒有被讀/寫訪問則對象從內(nèi)存中刪除(在另外的線程里面不定期維護) .expireAfterAccess(10, TimeUnit.MINUTES) //移除監(jiān)聽器,緩存項被移除時會觸發(fā) .removalListener(new RemovalListener () { @Override public void onRemoval(RemovalNotification rn) { //執(zhí)行邏輯操作 } }) //開啟Guava Cache的統(tǒng)計功能 .recordStats() .build(cacheLoader);
三.個人封裝的工具類
package com.xxx;import com.google.common.cache.*;import org.slf4j.Logger;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.TimeUnit;public class CacheManager { private static Logger log = Log.get(); /** 緩存項最大數(shù)量 */ private static final long GUAVA_CACHE_SIZE = 100000; /** 緩存時間:天 */ private static final long GUAVA_CACHE_DAY = 10; /** 緩存操作對象 */ private static LoadingCacheGLOBAL_CACHE = null; static { try { GLOBAL_CACHE = loadCache(new CacheLoader () { @Override public String load(Long key) throws Exception { // 處理緩存鍵不存在緩存值時的處理邏輯 return ""; } }); } catch (Exception e) { log.error("初始化Guava Cache出錯", e); } } /** * 全局緩存設置 * * 緩存項最大數(shù)量:100000 * 緩存有效時間(天):10 * * * @param cacheLoader * @return * @throws Exception */ private static LoadingCache loadCache(CacheLoader cacheLoader) throws Exception { LoadingCache cache = CacheBuilder.newBuilder() //緩存池大小,在緩存項接近該大小時, Guava開始回收舊的緩存項 .maximumSize(GUAVA_CACHE_SIZE) //設置時間對象沒有被讀/寫訪問則對象從內(nèi)存中刪除(在另外的線程里面不定期維護) .expireAfterAccess(GUAVA_CACHE_DAY, TimeUnit.DAYS) // 設置緩存在寫入之后 設定時間 后失效 .expireAfterWrite(GUAVA_CACHE_DAY, TimeUnit.DAYS) //移除監(jiān)聽器,緩存項被移除時會觸發(fā) .removalListener(new RemovalListener () { @Override public void onRemoval(RemovalNotification rn) { //邏輯操作 } }) //開啟Guava Cache的統(tǒng)計功能 .recordStats() .build(cacheLoader); return cache; } /** * 設置緩存值 * 注: 若已有該key值,則會先移除(會觸發(fā)removalListener移除監(jiān)聽器),再添加 * * @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); } } /** * 獲取緩存值 * 注:如果鍵不存在值,將調(diào)用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 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); } } /** * 獲取緩存項數(shù)量 * * @return */ public static long size() { long size = 0; try { size = GLOBAL_CACHE.size(); } catch (Exception e) { log.error("獲取緩存項數(shù)量出錯", e); } return size; }}
總結
1.移除機制
guava做cache時候數(shù)據(jù)的移除分為被動移除和主動移除兩種。
被動移除分為三種:1).基于大小的移除:數(shù)量達到指定大小,會把不常用的鍵值移除
2).基于時間的移除:expireAfterAccess(long, TimeUnit) 根據(jù)某個鍵值對最后一次訪問之后多少時間后移除 expireAfterWrite(long, TimeUnit) 根據(jù)某個鍵值對被創(chuàng)建或值被替換后多少時間移除
3).基于引用的移除:主要是基于java的垃圾回收機制,根據(jù)鍵或者值的引用關系決定移除
主動移除分為三種:1).單獨移除:Cache.invalidate(key)
2).批量移除:Cache.invalidateAll(keys)
3).移除所有:Cache.invalidateAll()
如果配置了移除監(jiān)聽器RemovalListener,則在所有移除的動作時會同步執(zhí)行該listener下的邏輯。
如需改成異步,使用:RemovalListeners.asynchronous(RemovalListener, Executor)
2.遇到的問題
1). 在put操作之前,如果已經(jīng)有該鍵值,會先觸發(fā)removalListener移除監(jiān)聽器,再添加
2). 配置了expireAfterAccess和expireAfterWrite,但在指定時間后沒有被移除。
解決方案:CacheBuilder在文檔上有說明
If expireAfterWrite or expireAfterAccess is requested entries may be evicted on each cache modification, on occasional cache accesses, or on calls to Cache.cleanUp(). Expired entries may be counted in Cache.size(), but will never be visible to read or write operations.
翻譯過來大概的意思是:CacheBuilder構建的緩存不會在特定時間自動執(zhí)行清理和回收工作,也不會在某個緩存項過期后馬上清理,它不會啟動一個線程來進行緩存維護,因為
a)線程相對較重
b)某些環(huán)境限制線程的創(chuàng)建。它會在寫操作時順帶做少量的維護工作,或者偶爾在讀操作時做
當然,也可以創(chuàng)建自己的維護線程,以固定的時間間隔調(diào)用Cache.cleanUp()。
感謝各位的閱讀!關于“基于LoadingCache實現(xiàn)Java本地緩存的方法”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!