亚洲 国产精品 日韩-亚洲 激情-亚洲 欧美 91-亚洲 欧美 成人日韩-青青青草视频在线观看-青青青草影院

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

手機站
千鋒教育

千鋒學習站 | 隨時隨地免費學

千鋒教育

掃一掃進入千鋒手機站

領取全套視頻
千鋒教育

關注千鋒學習站小程序
隨時隨地免費學習課程

當前位置:首頁  >  技術干貨  > 千鋒Java培訓分享如何設計一個本地緩存

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

來源:千鋒教育
發布人:劉老師
時間: 2020-07-08 18:05:00 1594202700

前言

最近在看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;

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

tags:
聲明:本站稿件版權均屬千鋒教育所有,未經許可不得擅自轉載。
10年以上業內強師集結,手把手帶你蛻變精英
請您保持通訊暢通,專屬學習老師24小時內將與您1V1溝通
免費領取
今日已有369人領取成功
劉同學 138****2860 剛剛成功領取
王同學 131****2015 剛剛成功領取
張同學 133****4652 剛剛成功領取
李同學 135****8607 剛剛成功領取
楊同學 132****5667 剛剛成功領取
岳同學 134****6652 剛剛成功領取
梁同學 157****2950 剛剛成功領取
劉同學 189****1015 剛剛成功領取
張同學 155****4678 剛剛成功領取
鄒同學 139****2907 剛剛成功領取
董同學 138****2867 剛剛成功領取
周同學 136****3602 剛剛成功領取
相關推薦HOT
99久久99精品久久久久久| 久久99国产精品尤物| 专干日本熟妇人妻| 玩弄少妇人妻中文字幕| 内射口爆少妇麻豆| 国产精品VA尤物在线观看| 99国产精品久久久蜜芽| 日本精品一区二区三区在线视频 | 丰满的继牳3中文字幕系列| 无码人妻一区二区三区免费看| 久久精品国产72国产精| 激情欧美成人久久综合| 免费国产无人区码卡二卡3卡| 快拨出天我是你母亲| 国产偷窥熟女精品视频| 51FUN吃瓜网-热心群众| 性欧美VIDEOFREE高清成| 内射到高潮的H小说| 护士HD老师FREE性ⅩⅩⅩ| 成人无码A级毛片免费| 中文亚洲AV片在线观看不卡| 亚洲AV无码成人精品区明星换面 | 99在线精品视频高潮喷吹| 凸凹人妻人人澡人人添| 欧美巨大乳BBWVIDEOS| 精品无码久久久久久久久| 国产丰滿老熟女多毛hD| 粗大黑人巨茎大战欧美成人免费看| 要灬要灬再深点受不了好舒服| 亚洲精品无码久久| 小婷又软又嫩又紧水又多| 欧美性猛交乱大交3| 精品国产三级A∨在线| 55大东北熟女啪啪嗷嗷叫| 亚洲精品99久久久久中文字幕| 亚洲AV成人午夜福利在线观看 | 亚洲AV无码成人网站在线观看| 18成禁人视频免费网站| 国产精品任我爽爆在线播放| 男人添女人下部高潮全视频| 性欧美18ⅩXOO极品FREE| AAAAA级大公开超高准确率| 人体艺术在线观看| 你真紧你这是要我的命吗| 没带罩子让他捏了一节课 | 性色AV一区二区三区| 亚洲日本VA一区二区三区| 中国女人FREE性HD| 波多野结衣av在线| 国产日产欧产精品品不卡| 成人无码视频免费播放| 国产精品后入内射日本在线观看 | 国产精品久久久久久婷婷| 哈昂~哈昂够了太多了男男| 精品少妇无码AV在线播放| 人妻互换精品一区二区| 日本熟妇色XXXXX日本妇| VPSWINDOWS另类极品| 精品无码日韩国产不卡AV| 色综合精品无码一区二区三区| 伊人AV超碰伊人久久久| 国产高清午夜人成在线观看| 欧美国产亚洲日韩在线二区| 亚洲乱码日产精品B| 哦┅┅快┅┅用力啊┅┅在线观看| 玩弄人妻少妇500系列网址 | 精品无码一区二区三区在线| 他趴在两腿中间舔我私密有事| 97国产精华最好的产品价格| 精品人妻潮喷久久久又裸又黄| 天天摸天天碰天天添中文无码| A级毛片在线观看| 久久久久精品电影一区二区三区| 天天看片天天AV免费观看| JLZZJLZZ全部女高潮| 久久中文字幕无码一区二区| 性无码免费一区二区三区屯线| 成人片黄网站色大片免费观看CN| 日韩AV片无码一区二区不卡电影| 日韩久久无码免费毛片软件| 小13箩利洗澡无码视频网站| 一边做一边喷17P| 成年视频APP短视频在线观看| 公交车伦流澡到高潮HNP| 久久久无码精品午夜| 日韩精品一区二区三区在线观看| 挺进邻居人妻雪白的身体韩国电影 | 孽火(硬汉)今又| 与子敌伦刺激对白播放| 精品无人区无码乱码大片国产| 无人区一码二码乱码区别在哪| 成人无号精品一区二区三区| 欧美亚洲精品中文字幕乱码| 2020精品国产自在现线看 | 日韩毛片无码永久免费看| 99久久免费国产精品| 蜜桃AV无码国产丝袜在线观看| 亚洲人成色777777网站| 护士被弄到高潮喷水抽搐| 亚洲AVSSS在线观看| 国产日产欧产精品精品推荐免费 | 少妇开裆肉丝自慰流白浆| 成 人 黄 色 网站 69| 人妻少妇 少妇人妻第一页 | 亚洲手机看片AV| 精品女同一区二区三区免费站| 亚洲A成人无码网站在线| 国产亚洲日韩一区二区三区| 午夜伦伦电影理论片大片| 国产精品无码V在线观看| 无码精品H动漫成人影院| 国产对白videos麻豆高潮| 熟妇人妻一区二区三区四区| 公天天吃我奶躁我的B| 成人A级毛片免费观看| 狠狠躁天天躁中文字幕| 艳妇臀荡乳欲伦69调教视频| 国产男女猛烈无遮挡免费视频| 女人自熨全过程直播| 亚洲精品成人片在线观看精品| 成人性欧美丨区二区三区| 毛卡5卡6卡7卡8入口| 亚洲AV无码一区二区二三区3p| 被医生吃奶吃高潮了H| 欧美一级 片内射欧美乱强| www高潮无码免费看| 人妻AVAV中文系列久久| 宝贝你夹得太紧了我都要断了| 日本丰满熟妇人妻aqq| 城中村勾搭老熟女啪啪| 天堂√中文最新版在线| 国产精品无码午夜福利| 亚洲AV无码久久| 久久国产精品日本波多野结衣| 阳茎伸入女人的阳道免费视频 | 日本裸体丰满少妇自慰喷奶水| 成人用品有限公司| 天天躁日日躁狠狠久久| 国产又粗又猛又爽又黄的视频免费黑人了 | 国产精品 高清 尿 小便 嘘嘘| 亚洲 丝袜 另类 校园 欧美| 娇小XXXXBXBⅨ中国XX| 一本大道久久东京热无码AV| 蜜桃AV一区二区三区| JAVAPARSERHD高潮| 色欲av蜜臀一区二区三区vr| 国产欧美一区二区精品性色| 亚洲精品无码久久久久久小说| 老头发狂的吸住她的乳尖| MM1313亚洲精品无码又大又| 色惰日本视频网站WWW| 国产日产亚洲系列最新| 亚洲欧美丝袜 动漫专区| 美女直播全婐APP免费| 宝贝这么湿想要吗| 无码人妻丰满熟妇区五十路| 精品国产肉丝袜久久| 2020久久天天躁狠狠躁夜夜| 日韩精品无码成人专区| 国产嫖妓一区二区三区无码| 亚洲无码一区二区三区| 欧美XXXX色视频在线观看| 厨房里挺进岳丰满大屁股| 香蕉久久夜色精品国产| 久久人人爽爽爽人久久久| WWW.一区二区三区在线 || 无码国产乱人伦偷精品视频| 精品无码一区二区三区在线| 99久RE热视频这里只有精品6| 天堂VA在线高清一区| 精品无码三级在线观看视频 | 国产女人精品视频国产灰线| 亚洲欧美一区二区成人片牛牛| 人妻一区二区三区Av毛片| 成人无码区免费A∨电影| 性姿势108式大全图解| 久久亚洲精品成人无码| 2021亚洲无码| 天无日天天射天天视| 精品国产不卡一区二区三区| 中文字幕无码日韩专区免费| 四虎无码永久在线影库网址一个人| 久久亚洲精品无码观看| 亚洲乱码日产精品BD在观看| 欧美黑人一级爽快片婬片高清 | FREE俄罗斯免费视频| 无码人妻精品一区二| 久久亚洲春色中文字幕久久久| 成·人免费午夜无码视频| 亚洲精品狼友在线播放| 人妻妺妺窝人体色777777| 好大好深好猛好爽视频| 97久久久精品综合88久久| 五十老熟女高潮嗷嗷叫| 妺妺窝人体色WWW在线一| 国产乱人伦偷精品视频AAA| 337P日本欧洲亚洲大胆精筑| 性XXXXBBBB农村小树林| 欧美牲交视频免费观看| 狠狠色丁香久久婷婷综合五月|