2. java快取-程序內快取
#程序內快取
程序內快取的概述就不說了,可以檢視:java快取概述
本篇文章主要說說常見的程序內快取,這裡分為兩類:自定義程序內快取、輕量級程序內快取框架。
##自定義程序快取
利用java的基本資料結構List、Map、Set等,自定義一個快取對應。
自定義程序快取示例:
import java.util.HashMap; public class MyCache { //測試程式碼 public static void main(String[] args) { CustomCache cache = CustomCache.instance(); cache.put("2313", 13213); cache.put("jkf1", 132); System.out.println(cache.get("jkf")); System.out.println(cache.get("jkf1")); } } //自定義快取示例,單利必須是要保證的 class CustomCache<V> { private static CustomCache instance = new CustomCache(); private HashMap<String, V> cache = new HashMap<>(); private CustomCache(){} public static CustomCache instance() { return instance; } public void put(String key, V t) { this.cache.put(key, t); } public V get(String key) { return cache.get(key); } }
上述自定義示例,就是簡單的包裝一個HahMap,對頻繁訪問的資料進行快取。自定義快取存在如下的缺點:
- 多執行緒併發訪問。
- 儲存資料過多,存在記憶體溢位,即沒有快取淘汰策略。
- 一些快取的統計資料無法提供。
當然上述缺陷,我們都可以在上述程式碼上,進行精細化開發,解決上述的缺點,但是這樣的開發量比較大,與初衷背離:我只是想簡簡單單的使用一下,不想再開發一個專業的快取。
輕量級程序內快取框架
主要是說google的guava cache,這個輕量級的執行緒內快取。
###使用guava cache
a. 引入方便,只需要引用google開源java類庫即可,guava cache只是其中的一個包。
b. 使用簡潔,Guava cache對泛型具有良好的支援,支援多種型別的快取。例如:
String=Object,Integer=Object。
c. 不需要配置檔案,直接通過程式碼配置快取的各種引數,例如:併發執行緒量(concurrencyLevel,寫的執行緒數)、容器初始容量(initialCapacity)、快取移除通知(removalListener)、快取不命中的載入資料方法(CacheLoader的load)、快取失效策略(expireAfterWrite、maximumSize(LRU)),當然上述方法中“快取不命中的載入資料方法”只有特殊的快取例項支援。
d. 最特殊的:guava cache 是單執行緒,guava cache不會建立執行緒來維護快取。
###使用示例
guava cache的快取例項型別有多種,這裡只是簡單的介紹“可載入快取(LoadingCache)”的使用,其他型別的快取例項,請看下一篇專門的guava cache架構分析。
通過時間失效進行快取淘汰
public static void main(String[] args) {
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
//快取失效策略:寫後30分鐘
.expireAfterWrite(30L, TimeUnit.MINUTES)
//快取未命中的策略:通過load方法查詢獲取資料
.build(new CacheLoader<String, Integer>() {
@Override
public Integer load(String key) throws Exception {
return new Random().nextInt(10);
}
});
}
更完善的示例
public static void main(String[] args) {
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.concurrencyLevel(8)
.initialCapacity(10)
.maximumSize(100)
.recordStats()
.removalListener(new RemovalListener<String, Integer>() {
@Override
public void onRemoval(RemovalNotification<String, Integer> notification) {
}
}).build(new CacheLoader<String, Integer>() {
@Override
public Integer load(String key) throws Exception {
return new Random().nextInt(10);
}
});
}
###什麼時候使用guava cache
使用場景
- 你願意消耗一些記憶體空間來提升速度。
- 你預料到某些鍵會被查詢一次以上。
- 快取中存放的資料總量不會超出記憶體容量。(Guava Cache是單個應用執行時的本地快取。它不能把資料存放到檔案或外部伺服器。如果這不符合你的需求,請嘗試Memcached這類工具)
- guava cache可以快取 少量的 頻繁查詢 的資料。
- guava cache的快取失效,並不是立刻失效,而是延遲失效,原因:guava cache並不會啟動執行緒,而是利用利用當前執行緒,進行快取失效處理,例如會在寫操作後呼叫快取清理,如果寫操作太少會在讀操作進行快取清理。當然如果對快取清理要求嚴格,可以自己建立維護執行緒,進行快取清理工作,例如:定時任務、其他執行緒
- 因為使用的是快取,所以需要考慮快取一致性對需求的要求。
- 因為是程序內快取,guava cache沒有提供快取的持久化。
- Guava cache可以根據不同的業務設定不同的cache,可以做到同一業務的同一處理,但是又會引發快取的離散,這個需要衡量。
guava cache的框架分析,見下一篇