千鋒教育-做有情懷、有良心、有品質的IT職業教育機構

編程硬核資料庫,
隨查隨看隨問答!

HTML5領取課程大綱
領取視頻教程
Java領取課程大綱
領取視頻教程
Python領取課程大綱
領取視頻教程
全鏈路設計領取課程大綱
領取視頻教程
云計算領取課程大綱
領取視頻教程
軟件測試領取課程大綱
領取視頻教程
大數據領取課程大綱
領取視頻教程
智能物聯網領取課程大綱
領取視頻教程
Unity游戲開發領取課程大綱
領取視頻教程
網絡安全領取課程大綱
領取視頻教程
互聯網營銷領取課程大綱
領取視頻教程
GO語言開發領取課程大綱
領取視頻教程
返回頂部
當前位置:首頁  >  關于學院  >  技術論壇  >  正文

千鋒Java培訓分享如何設計一個本地緩存

時間:2020-07-08 18:05     來源:千鋒教育 作者:劉老師
分享: 更多

前言

最近在看Mybatis的源碼,剛好看到緩存這一塊,Mybatis提供了一級緩存和二級緩存;一級緩存相對來說比較簡單,功能比較齊全的是二級緩存,基本上滿足了一個緩存該有的功能;當然如果拿來和專門的緩存框架如ehcache來對比可能稍有差距;本文千鋒Java培訓講師帶大家來整理一下實現一個本地緩存都應該需要考慮哪些東西。

考慮點

考慮點主要在數據用何種方式存儲,能存儲多少數據,多余的數據如何處理等幾個點,下面我們來詳細的介紹每個考慮點,以及該如何去實現;

1.數據結構

首要考慮的就是數據該如何存儲,用什么數據結構存儲,最簡單的就直接用Map來存儲數據;或者復雜的如redis一樣提供了多種數據類型哈希,列表,集合,有序集合等,底層使用了雙端鏈表,壓縮列表,集合,跳躍表等數據結構;

2.對象上限

因為是本地緩存,內存有上限,所以一般都會指定緩存對象的數量比如1024,當達到某個上限后需要有某種策略去刪除多余的數據;

3.清除策略

上面說到當達到對象上限之后需要有清除策略,常見的比如有LRU(最近最少使用)、FIFO(先進先出)、LFU(最近最不常用)、SOFT(軟引用)、WEAK(弱引用)等策略;

4.過期時間

除了使用清除策略,一般本地緩存也會有一個過期時間設置,比如redis可以給每個key設置一個過期時間,這樣當達到過期時間之后直接刪除,采用清除策略+過期時間雙重保證;

5.線程安全

像redis是直接使用單線程處理,所以就不存在線程安全問題;而我們現在提供的本地緩存往往是可以多個線程同時訪問的,所以線程安全是不容忽視的問題;并且線程安全問題是不應該拋給使用者去保證;

6.簡明的接口

提供一個傻瓜式的對外接口是很有必要的,對使用者來說使用此緩存不是一種負擔而是一種享受;提供常用的get,put,remove,clear,getSize方法即可;

7.是否持久化

這個其實不是必須的,是否需要將緩存數據持久化看需求;本地緩存如ehcache是支持持久化的,而guava是沒有持久化功能的;分布式緩存如redis是有持久化功能的,memcached是沒有持久化功能的;

8.阻塞機制

在看Mybatis源碼的時候,二級緩存提供了一個blocking標識,表示當在緩存中找不到元素時,它設置對緩存鍵的鎖定;這樣其他線程將等待此元素被填充,而不是命中數據庫;其實我們使用緩存的目的就是因為被緩存的數據生成比較費時,比如調用對外的接口,查詢數據庫,計算量很大的結果等等;這時候如果多個線程同時調用get方法獲取的結果都為null,每個線程都去執行一遍費時的計算,其實也是對資源的浪費;比較好的辦法是只有一個線程去執行,其他線程等待,計算一次就夠了;但是此功能基本上都交給使用者來處理,很少有本地緩存有這種功能;

如何實現

以上大致介紹了實現一個本地緩存我們都有哪些需要考慮的地方,當然可能還有其他沒有考慮到的點;下面繼續看看關于每個點都應該如何去實現,重點介紹一下思路;

1.數據結構

本地緩存最常見的是直接使用Map來存儲,比如guava使用ConcurrentHashMap,ehcache也是用了ConcurrentHashMap,Mybatis二級緩存使用HashMap來存儲:

Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>()

Mybatis使用HashMap本身是非線程安全的,所以可以看到起內部使用了一個SynchronizedCache用來包裝,保證線程的安全性;

當然除了使用Map來存儲,可能還使用其他數據結構來存儲,比如redis使用了雙端鏈表,壓縮列表,整數集合,跳躍表和字典;當然這主要是因為redis對外提供的接口很豐富除了哈希還有列表,集合,有序集合等功能;

2.對象上限

本地緩存常見的一個屬性,一般緩存都會有一個默認值比如1024,在用戶沒有指定的情況下默認指定;當緩存的數據達到指定最大值時,需要有相關策略從緩存中清除多余的數據這就涉及到下面要介紹的清除策略;

3.清除策略

配合對象上限之后使用,場景的清除策略如:LRU(最近最少使用)、FIFO(先進先出)、LFU(最近最不常用)、SOFT(軟引用)、WEAK(弱引用);

LRU:Least Recently Used的縮寫最近最少使用,移除最長時間不被使用的對象;常見的使用LinkedHashMap來實現,也是很多本地緩存默認使用的策略;

FIFO:先進先出,按對象進入緩存的順序來移除它們;常見使用隊列Queue來實現;

LFU:Least Frequently Used的縮寫大概也是最近最少使用的意思,和LRU有點像;區別點在LRU的淘汰規則是基于訪問時間,而LFU是基于訪問次數的;可以通過HashMap并且記錄訪問次數來實現;

SOFT:軟引用基于垃圾回收器狀態和軟引用規則移除對象;常見使用SoftReference來實現;

WEAK:弱引用更積極地基于垃圾收集器狀態和弱引用規則移除對象;常見使用WeakReference來實現;

4.過期時間

設置過期時間,讓緩存數據在指定時間過后自動刪除;常見的過期數據刪除策略有兩種方式:被動刪除和主動刪除;

被動刪除:每次進行get/put操作的時候都會檢查一下當前key是否已經過期,如果過期則刪除,類似如下代碼:

if (System.currentTimeMillis() - lastClear > clearInterval) {

clear();

}

主動刪除:專門有一個job在后臺定期去檢查數據是否過期,如果過期則刪除,這其實可以有效的處理冷數據;

5.線程安全

盡量用線程安全的類去存儲數據,比如使用ConcurrentHashMap代替HashMap;或者提供相應的同步處理類,比如Mybatis提供了SynchronizedCache:

public synchronized void putObject(Object key, Object object) {

...省略...

}

@Override

public synchronized Object getObject(Object key) {

...省略...

}

6.簡明的接口

提供常用的get,put,remove,clear,getSize方法即可,比如Mybatis的Cache接口:

public interface Cache {

String getId();

void putObject(Object key, Object value);

Object getObject(Object key);

Object removeObject(Object key);

void clear();

int getSize();

ReadWriteLock getReadWriteLock();

}

再來看看guava提供的Cache接口,相對來說也是比較簡潔的:

public interface Cache<K, V> {

V getIfPresent(@CompatibleWith("K") Object key);

V get(K key, Callable<? extends V> loader) throws ExecutionException;

ImmutableMap<K, V> getAllPresent(Iterable<?> keys);

void put(K key, V value);

void putAll(Map<? extends K, ? extends V> m);

void invalidate(@CompatibleWith("K") Object key);

void invalidateAll(Iterable<?> keys);

void invalidateAll();

long size();

CacheStats stats();

ConcurrentMap<K, V> asMap();

void cleanUp();

}

7.是否持久化

持久化的好處是重啟之后可以再次加載文件中的數據,這樣就起到類似熱加載的功效;比如ehcache提供了是否持久化磁盤緩存的功能,將緩存數據存放在一個.data文件中;

diskPersistent="false" //是否持久化磁盤緩存

redis更是將持久化功能發揮到極致,慢慢的有點像數據庫了;提供了AOF和RDB兩種持久化方式;當然很多情況下可以配合使用兩種方式;

8.阻塞機制

除了在Mybatis中看到了BlockingCache來實現此功能,之前在看<<java并發編程實戰>>的時候其中有實現一個很完美的緩存,大致代碼如下:

public class Memoizerl<A, V> implements Computable<A, V> {

private final Map<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();

private final Computable<A, V> c;

public Memoizerl(Computable<A, V> c) {

this.c = c;

}

@Override

public V compute(A arg) throws InterruptedException, ExecutionException {

while (true) {

Future<V> f = cache.get(arg);

if (f == null) {

Callable<V> eval = new Callable<V>() {

@Override

public V call() throws Exception {

return c.compute(arg);

}

};

FutureTask<V> ft = new FutureTask<V>(eval);

f = cache.putIfAbsent(arg, ft);

if (f == null) {

f = ft;

ft.run();

}

try {

return f.get();

} catch (CancellationException e) {

cache.remove(arg, f);

}

}

}

}

}

compute是一個計算很費時的方法,所以這里把計算的結果緩存起來,但是有個問題就是如果兩個線程同時進入此方法中怎么保證只計算一次,這里最核心的地方在于使用了ConcurrentHashMap的putIfAbsent方法,同時只會寫入一個FutureTask;

總結:要設計一個本地緩存都需要考慮哪些點:數據結構,對象上限,清除策略,過期時間,線程安全,阻塞機制,實用的接口,是否持久化;當然肯定有其他考慮點,歡迎補充。

相關文章

  • 北京總部地址:北京市海淀區寶盛北里西區28號中關村智誠科創大廈4層
    北京沙河校區:北京市昌平區沙陽路18號北京科技職業技術學院廣場服務樓
    咨詢電話:400-811-9990
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、Linux云計算+網絡安全培訓、互聯網營銷培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 深圳校區地址:深圳市寶安區寶安大道5010號西部硅谷B座A區6層A605/B座C區1層108
    咨詢電話:0755-23015275/23015546-801/86660670
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、Linux云計算+網絡安全培訓、互聯網營銷培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 上海校區地址:上海市寶山區同濟支路199號智慧七立方3號樓2-4層
    咨詢電話:400-811-9990 021-65233829-609
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、Linux云計算+網絡安全培訓、互聯網營銷培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 廣州校區地址:廣州市天河區元崗路200號慧通產業園B9三層
    咨詢電話:020-87088521
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 鄭州二七區校區地址:鄭州市二七區航海中路60號海為科技園C區10層
    鄭州高新區校區地址:鄭州市高新區金梭路與銀杏路交叉口教育科技產業園南門D座4層
    咨詢電話:0371-55191750/18610973027
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 大連校區地址:遼寧省大連市高新園區愛賢街10號大連設計城A座901
    咨詢電話:400-811-9990
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 武漢金融港校區地址:武漢市東湖高新技術開發區光谷大道77號金融港B18棟3樓
    武漢智慧園校區地址:武漢市東湖高新技術開發區光谷大道61號智慧園21棟2樓
    咨詢電話:027-59313371
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 成都校區地址:成都市高新區肖家河沿街138號肖家河大廈三樓
    咨詢電話:18628039301
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 西安校區地址:西安市雁塔區高新六路52號立人科技C座西區4樓
    咨詢電話:029-85363390
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 杭州旺田校區:浙江省杭州市江干區九堡旺田書畫城A座4層
    杭州龍馳校區:浙江省杭州市下沙經濟技術開發區元成路199號龍馳智慧谷B座7層
    咨詢電話:400-811-9990 0571-86893632/0571-86094032
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 青島校區地址:青島市市北區龍城路31號卓越世紀中心4號樓5層
    咨詢電話:18610973011
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 重慶校區地址:重慶市高新區科園一路2號大西洋國際12-1
    咨詢電話:400-811-9990 023-68883009
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 長沙校區地址:湖南省長沙市岳麓區麓谷企業廣場A2棟三單元306號
    咨詢電話:0731-85513210
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 哈爾濱校區地址:哈爾濱市松北區世澤路689號 科技創新城4號樓1101
    咨詢電話:400-811-9990/0451-87173191
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 南京校區地址:南京市建鄴區應天大街780號弘輝產業園1棟2層
    咨詢電話:400-811-9990
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 太原校區地址:太原市小店區長治路230號能源互聯網大廈6層
    咨詢電話:400-811-9990 16603513433
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 沈陽校區地址:遼寧省沈陽市渾南區世紀路16號東大軟件園B園B1座A201
    咨詢電話:400-811-9990
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 合肥校區地址:合肥市包河區徽州大道396號東方廣場B座12A
    咨詢電話:400-811-9990
    面授課程:HTML5大前端培訓、JavaEE+分布式開發培訓、Python全棧+人工智能培訓、全鏈路UI/UE設計培訓、云計算培訓、全棧軟件測試培訓、大數據+人工智能培訓、智能物聯網+嵌入式培訓、Unity游戲開發培訓、Go語言開發培訓、PHP全棧+服務器集群培訓、網絡安全培訓、互聯網營銷培訓、好程序員
    認證課程:軟考、Adobe認證、PMP認證、紅帽RHCE認證
  • 千鋒教育服務號

    了解千鋒動態
    關注千鋒教育服務號

  • 千鋒教育移動站

    掃一掃快速進入
    千鋒移動端頁面

  • 千鋒互聯服務號

    掃碼匿名提建議
    直達CEO信箱

[an error occurred while processing the directive] 欧美情色小说图片