使用場(chǎng)景
在 Java 應(yīng)用中佛掖,對(duì)于訪問頻率高妖碉,更新少的數(shù)據(jù),通常的方案是將這類數(shù)據(jù)加入緩存中芥被。相對(duì)從數(shù)據(jù)庫中讀取來說欧宜,讀緩存效率會(huì)有很大提升。
在集群環(huán)境下拴魄,常用的分布式緩存有 Redis 冗茸、 Memcached 等席镀。但在某些業(yè)務(wù)場(chǎng)景上,可能不需要去搭建一套復(fù)雜的分布式緩存系統(tǒng)夏漱,在單機(jī)環(huán)境下豪诲,通常是會(huì)希望使用內(nèi)部的緩存( LocalCache )。
實(shí)現(xiàn)
這里提供了兩種 LocalCache 的實(shí)現(xiàn)麻蹋,一種是基于 ConcurrentHashMap 實(shí)現(xiàn)基本本地緩存跛溉,另外一種是基于 LinkedHashMap 實(shí)現(xiàn) LRU 策略的本地緩存扮授。
基于ConcurrentHashMap的實(shí)現(xiàn)
static {
timer = new Timer();
map = new ConcurrentHashMap<>();
}
以 ConcurrentHashMap 作為緩存的存儲(chǔ)結(jié)構(gòu)。因?yàn)?ConcurrentHashMap 的線程安全的专肪,所以基于此實(shí)現(xiàn)的 LocalCache 在多線程并發(fā)環(huán)境的操作是安全的刹勃。在 JDK1.8 中, ConcurrentHashMap 是支持完全并發(fā)讀嚎尤,這對(duì)本地緩存的效率也是一種提升荔仁。通過調(diào)用 ConcurrentHashMap 對(duì) map 的操作來實(shí)現(xiàn)對(duì)緩存的操作。
私有構(gòu)造函數(shù)
privateLocalCache(){
}
LocalCache 是工具類芽死,通過私有構(gòu)造函數(shù)強(qiáng)化不可實(shí)例化的能力乏梁。
緩存清除機(jī)制
/**
* 清除緩存任務(wù)類
*/
static classCleanWorkerTaskextendsTimerTask{
private String key;
publicCleanWorkerTask(String key){
this.key = key;
}
publicvoidrun(){
LocalCache.remove(key);
}
}
清理失效緩存是由 Timer 類實(shí)現(xiàn)的。內(nèi)部類 CleanWorkerTask 繼承于 TimerTask 用戶清除緩存关贵。每當(dāng)新增一個(gè)元素的時(shí)候遇骑,都會(huì)調(diào)用 timer.schedule 加載清除緩存的任務(wù)。
基于LinkedHashMap的實(shí)現(xiàn)
以 LinkedHashMap 作為緩存的存儲(chǔ)結(jié)構(gòu)揖曾。主要是通過 LinkedHashMap 的按照訪問順序的特性來實(shí)現(xiàn) LRU 策略落萎。
LRU
LRU 是 Least Recently Used 的縮寫,即最近最久未使用炭剪。 LRU 緩存將會(huì)利用這個(gè)算法來淘汰緩存中老的數(shù)據(jù)元素练链,從而優(yōu)化內(nèi)存空間。
基于LRU策略的map
這里利用 LinkedHashMap 來實(shí)現(xiàn)基于 LRU 策略的 map 奴拦。通過調(diào)用父類 LinkedHashMap 的構(gòu)造函數(shù)來實(shí)例化 map 媒鼓。參數(shù) accessOrder 設(shè)置為 true 保證其可以實(shí)現(xiàn) LRU 策略。
static classLRUMap<K,V>extendsLinkedHashMap<K,V>{
... // 省略部分代碼
publicLRUMap(intinitialCapacity,floatloadFactor){
super(initialCapacity, loadFactor, true);
}
... // 省略部分代碼
/**
* 重寫LinkedHashMap中removeEldestEntry方法;
* 新增元素的時(shí)候,會(huì)判斷當(dāng)前map大小是否超過DEFAULT_MAX_CAPACITY,超過則移除map中最老的節(jié)點(diǎn);
*
* @param eldest
* @return
*/
protectedbooleanremoveEldestEntry(Map.Entry<K, V> eldest){
return size() > DEFAULT_MAX_CAPACITY;
}
}
線程安全
/**
* 讀寫鎖
*/
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock rLock = readWriteLock.readLock();
private final Lock wLock = readWriteLock.writeLock();
LinkedHashMap 并不是線程安全错妖,如果不加控制的在多線程環(huán)境下使用的話隶糕,會(huì)有問題。所以在 LRUMap 中引入了 ReentrantReadWriteLock 讀寫鎖站玄,來控制并發(fā)問題枚驻。
緩存淘汰機(jī)制
protectedbooleanremoveEldestEntry(Map.Entry<K, V> eldest){
return size() > DEFAULT_MAX_CAPACITY;
}
此處重寫 LinkedHashMap 中 removeEldestEntry 方法, 當(dāng)緩存新增元素的時(shí)候,會(huì)判斷當(dāng)前 map 大小是否超過 DEFAULT_MAX_CAPACITY ,超過則移除map中最老的節(jié)點(diǎn)株旷。
緩存清除機(jī)制
緩存清除機(jī)制與 ConcurrentHashMap 的實(shí)現(xiàn)一致再登,均是通過 timer 實(shí)現(xiàn)尔邓。
推薦大家閱讀:
Java高級(jí)架構(gòu)學(xué)習(xí)資料分享+架構(gòu)師成長(zhǎng)之路?
個(gè)人整理了更多資料以PDF文件的形式分享給大家,需要查閱的程序員朋友可以來免費(fèi)領(lǐng)取锉矢。還有我的學(xué)習(xí)筆記PDF文件也免費(fèi)分享給有需要朋友梯嗽!
順便給大家推薦一個(gè)Java技術(shù)交流群:473984645里面會(huì)分享一些資深架構(gòu)師錄制的視頻資料:有Spring,MyBatis沽损,Netty源碼分析灯节,高并發(fā)、高性能绵估、分布式炎疆、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化国裳、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系形入。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多缝左!