Java?guava框架LoadingCache及CacheBuilder本地小容量緩存框架總結
Guava Cache本地緩存框架介紹
主要是一種將本地數據緩存到內存中,但數據量并不能太大,否則將會占用過多的內存,雖然框架本身已經做了相當的數據回收,但還是不可以濫用,需要符合以下優(yōu)點場景,才是合適使用,訪問內存的速度快于訪問 redis 等數據庫。
有點以及需求場景:
- 對性能有非常高的要求
- 愿意消耗一些內存空間來提升速度
- 預計到某些鍵會被多次查詢
- 緩存中存放的數據總量不會超出內存容量
關鍵點是:有頻繁訪問的數據,且這些數據本身占用內存量很少,將這些數據存儲到該緩存框架中管理以提供性能。
提供的優(yōu)勢能力
- 緩存可以設置過期時間,并提供數據過多時的淘汰機制
- 是線程安全的,支持并發(fā)讀入和寫入
- 緩存獲取不到時可以從數據源獲取并加入到緩存中,GuavaCache 可以使用 CacheLoader 的load 方法控制,對同一個key,只允許一個請求去讀源并回填緩存,其他請求阻塞等待
- 可以查看緩存的加載獲取信息等
使用以及方法
Maven 依賴:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> </dependency>
最簡單的構建案例:
Cache<String, Object> cache = CacheBuilder.newBuilder().build(); cache.put("aaa", 156484);
與Map類似,獲取時使用get() 方法即可獲取到放入其中的數據。
通過 CacheBuilder 創(chuàng)建 Cache 對象,存儲類似于Map 構建方法為鏈式構造,類似于 builder 建造者模式,返回均為當前對象本身,調用 build 方法后結束構造。
CacheBuilder.newBuilder() 后的一些構建參數方法介紹:
initialCapacity:緩存的初始數據容量大小,一般要貼合實際否則會造成資源浪費
maximumSize:緩存中可包含最大 entry 數量,超過數量限制后淘汰 entry,接近最大值時淘汰不常用數據,設置為 0 時為不使用緩存的場景,用于測試數據加載
過期時間設置
expireAfterAccess:數據寫入后被訪問對象多久沒被訪問認為過期
expireAfterWrite: 數據被寫入到緩存后一直未更新多久后過期
可以如下寫:
Cache<String, Object> cache = CacheBuilder.newBuilder() .initialCapacity(5) .maximumSize(10) .expireAfterWrite(10, TimeUnit.MINUTES).build(); cache.put("154", "djawbdawd");
過期時間單位通過 TimeUnit 后的控制,時分秒均可
弱軟引用 (weakKeys, weakValues, softValues)
weakKeys
將緩存中的key設置成weakKey模式。
默認情況下,會使用“強關系”來保存key值。當設置為weakKey時,會使用 “==” 來匹配key值。在使用weakKey的情況下,數據可能會被GC。數據被GC后,可能仍然會被size方法計數,但是對其執(zhí)行read或write方法已經無效。
weakValues
將緩存中的數據設置為weakValues模式。
啟用時,某些數據會被GC。默認情況下會使用“強關系”來保存key值。當設置為weakValue時,會使用 “==” 來匹配value值。數據被GC后,可能仍然會被size方法計數,但是對其執(zhí)行read或write方法已經無效。
softValues
將緩存中的數據設置為softValues模式。
啟用時,所有的數據都使用SoftReference類對緩存中的數據進行包裹(就是在SoftReference實例中存儲真實的數據)。使用SoftReference包裹的數據,會被全局垃圾回收管理器托管,按照LRU的原則來定期GC數據。數據被GC后,可能仍然會被size方法計數,但是對其執(zhí)行read或write方法已經無效。
這些同樣在 CacheBuilder.newBuilder() 后設置。
主動刪除數據
當通過 builder 創(chuàng)建對象完成后,可以通過以下方式清除數據:
invalidateAll:清除全部數據,入參為 Iterable 類型參數,即 一般的List 集合即可,內容為所有的 key
invalidate:單一刪除,入參為 key
刪除監(jiān)聽器
即用于監(jiān)控緩存中的數據,當數據被刪除時會被觸發(fā)
類似如下代碼:
RemovalListener<String, String> listener = new RemovalListener<String, Object>() { public void onRemoval(RemovalNotification<String, String> notification) { // notification.getKey(); // 當前刪除對象的 key // notification.getValue(); // 當前刪除對象的 value } }; Cache<String, Object> cache = CacheBuilder.newBuilder() .maximumSize(5) // 添加移除監(jiān)聽器 .removalListener(listener) .build();
值得注意的是,這里的刪除不僅是主動刪除,當達到容量上限或者過期或由于其他策略導致數據消失時也認為是刪除
一般cache 主動加載數據
即當緩存中獲取不到指定 key 對應的 value 時,需要主動去其他途徑獲?。?/p>
寫法類似如下,需要提供獲取的實現方法:
Cache<String, Object> cache = CacheBuilder.newBuilder() .initialCapacity(5) .maximumSize(10) .expireAfterWrite(10, TimeUnit.MINUTES).build(); cache.put("154", "djawbdawd"); try { cache.get("aaa", new Callable<Object>() { @Override public Object call() throws Exception { // 具體如何獲取 // 方法的返回值即為 當前key 對應的value 并將會加入到緩存中 return null; } }); } catch (ExecutionException e) { e.printStackTrace(); }
需要在 Callable 內的方法重寫獲取實際數據的方法,方法的返回值即為 當前key 對應的value 并將會加入到緩存中,同時如果存在多個線程同時獲取同一個不存在的 key,那么將只有一個被執(zhí)行,其他需要等待。且一個線程獲取后,其他線程將也可以獲取這些數據。
統計信息
創(chuàng)建cache 對象時調用**.recordStats()** 后將開啟統計,可以通過 cache.stats() 獲取緩存
例如:
Cache<String, Object> cache = CacheBuilder.newBuilder() .initialCapacity(5) .maximumSize(10) .recordStats() .expireAfterWrite(10, TimeUnit.MINUTES).build(); cache.put("154", "djawbdawd"); try { cache.get("aaa", new Callable<Object>() { @Override public Object call() throws Exception { // ....... return null; } }); } catch (ExecutionException e) { e.printStackTrace(); } cache.stats();
較常用的 LoadingCache
LoadingCache 是 Cache的子接口 ,相比于Cache,當從LoadingCache中讀取一個指定key的記錄時,如果該記錄不存在,則LoadingCache可以自動執(zhí)行加載數據到緩存的操作,定義時需要重寫加載方法。
LoadingCache接口的定義如下:
CacheLoader<String, String> loader = new CacheLoader<>() { // 加載沒有的數據的方法 public String load(String key) throws Exception { // ............. return null; } }; LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder() .maximumSize(5) .build(loader);
或如下:
LoadingCache<String, Object> infoItemCache = CacheBuilder.newBuilder() .initialCapacity(5) .maximumSize(10) .expireAfterAccess(3, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() { // 使用 LoadingCache 重寫加載方法, 重寫后當無法從緩存中獲取到key 對應的值時將執(zhí)行重寫的load 方法,且返回值將成為入參key 對應的Value并存儲 @Override public Object load(String s) throws Exception { // ............ return null; } });
可以自定義簡單工具如下:
import com.dtdream.dthink.dtalent.dmall.dataresource.catalog.model.metadata.MetadataBlock; import com.dtdream.dthink.dtalent.dmall.dataresource.catalog.service.catalog.ICatalogTemplateService; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class MyCache { /** * 初始化緩存容量大小 */ private static final int INITIAL_CAPACITY = 5; /** * 緩存中可包含最大 entry 數量,超過數量限制后淘汰 entry,接近最大值時淘汰不常用數據,設置為 0 時為不使用緩存的場景,用于測試數據加載 */ private static final long MAXIMUM_SIZE = 10; /** * 放入緩存后指定時間內沒有被訪問將過期 */ private static final long EXPIRE_AFTER_ACCESS = 5; /** * cache 子接口, 緩存對象 */ private static LoadingCache<String, Object> infoItemCache; // 初始化緩存對象 static { infoItemCache = CacheBuilder.newBuilder().initialCapacity(INITIAL_CAPACITY).maximumSize(MAXIMUM_SIZE) .expireAfterAccess(EXPIRE_AFTER_ACCESS, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() { // 使用 LoadingCache 重寫加載方法, 重寫后當無法從緩存中獲取到key 對應的值時將執(zhí)行重寫的load 方法,且返回值將成為入參key 對應的Value并存儲 @Override public Object load(String s) throws Exception { // ............... return null; } }); } /** * 從緩存中獲取數據,若不存在則重新查詢 * @return */ public static Object getFromCache(String key) throws ExecutionException { Object data = infoItemCache.get(key); return data; } }
若需要從Spring 獲取Bean 服務,則可以通過 Spring 的 applicationConext 去獲取
到此這篇關于Java guava框架 LoadingCache,CacheBuilder 本地小容量緩存框架學習以及總結的文章就介紹到這了,更多相關Java guava框架 LoadingCache內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
深入分析JAVA 多線程--interrupt()和線程終止方式
這篇文章主要介紹了JAVA 多線程--interrupt()和線程終止方式的的相關資料,文中代碼非常細致,幫助大家更好的理解和學習,感興趣的朋友可以了解下2020-06-06Spring中的@Value和@PropertySource注解詳解
這篇文章主要介紹了Spring中的@Value和@PropertySource注解詳解,@PropertySource:讀取外部配置文件中的key-value保存到運行的環(huán)境變量中,本文提供了部分實現代碼,需要的朋友可以參考下2023-11-11