Java LocalCache 本地緩存的實(shí)現(xiàn)實(shí)例
源碼地址: GitHub
使用場(chǎng)景
在Java應(yīng)用中,對(duì)于訪問(wèn)頻率高,更新少的數(shù)據(jù),通常的方案是將這類數(shù)據(jù)加入緩存中。相對(duì)從數(shù)據(jù)庫(kù)中讀取來(lái)說(shuō),讀緩存效率會(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)?code>ConcurrentHashMap的線程安全的,所以基于此實(shí)現(xiàn)的LocalCache在多線程并發(fā)環(huán)境的操作是安全的。在JDK1.8中,ConcurrentHashMap是支持完全并發(fā)讀,這對(duì)本地緩存的效率也是一種提升。通過(guò)調(diào)用ConcurrentHashMap對(duì)map的操作來(lái)實(shí)現(xiàn)對(duì)緩存的操作。
私有構(gòu)造函數(shù)
private LocalCache() {
}
LocalCache是工具類,通過(guò)私有構(gòu)造函數(shù)強(qiáng)化不可實(shí)例化的能力。
緩存清除機(jī)制
/**
* 清除緩存任務(wù)類
*/
static class CleanWorkerTask extends TimerTask {
private String key;
public CleanWorkerTask(String key) {
this.key = key;
}
public void run() {
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)。主要是通過(guò)LinkedHashMap的按照訪問(wèn)順序的特性來(lái)實(shí)現(xiàn)LRU策略。
LRU
LRU是Least Recently Used的縮寫,即最近最久未使用。LRU緩存將會(huì)利用這個(gè)算法來(lái)淘汰緩存中老的數(shù)據(jù)元素,從而優(yōu)化內(nèi)存空間。
基于LRU策略的map
這里利用LinkedHashMap來(lái)實(shí)現(xiàn)基于LRU策略的map。通過(guò)調(diào)用父類LinkedHashMap的構(gòu)造函數(shù)來(lái)實(shí)例化map。參數(shù)accessOrder設(shè)置為true保證其可以實(shí)現(xiàn)LRU策略。
static class LRUMap<K, V> extends LinkedHashMap<K, V> {
... // 省略部分代碼
public LRUMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
... // 省略部分代碼
/**
* 重寫LinkedHashMap中removeEldestEntry方法;
* 新增元素的時(shí)候,會(huì)判斷當(dāng)前map大小是否超過(guò)DEFAULT_MAX_CAPACITY,超過(guò)則移除map中最老的節(jié)點(diǎn);
*
* @param eldest
* @return
*/
protected boolean removeEldestEntry(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ì)有問(wèn)題。所以在LRUMap中引入了ReentrantReadWriteLock讀寫鎖,來(lái)控制并發(fā)問(wèn)題。
緩存淘汰機(jī)制
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > DEFAULT_MAX_CAPACITY;
}
此處重寫LinkedHashMap中removeEldestEntry方法, 當(dāng)緩存新增元素的時(shí)候,會(huì)判斷當(dāng)前map大小是否超過(guò)DEFAULT_MAX_CAPACITY,超過(guò)則移除map中最老的節(jié)點(diǎn)。
緩存清除機(jī)制
緩存清除機(jī)制與ConcurrentHashMap的實(shí)現(xiàn)一致,均是通過(guò)timer實(shí)現(xiàn)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java 位運(yùn)算符>>與>>>區(qū)別案例詳解
這篇文章主要介紹了Java 位運(yùn)算符>>與>>>區(qū)別案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
HandlerMapping之RequestMappingHandlerMapping作用詳解
這篇文章主要介紹了HandlerMapping之RequestMappingHandlerMapping作用詳解,HandlerMapping是用來(lái)尋找Handler的,并不與Handler的類型或者實(shí)現(xiàn)綁定,而是根據(jù)需要定義的,那么為什么要單獨(dú)給@RequestMapping實(shí)現(xiàn)一個(gè)HandlerMapping,需要的朋友可以參考下2023-10-10
MyBatis-Plus的物理刪除和邏輯刪除(使用場(chǎng)景)
數(shù)據(jù)庫(kù)中的數(shù)據(jù)刪除會(huì)分為兩種:物理刪除 和 邏輯刪除,接下來(lái)通過(guò)本文給大家介紹MyBatis-Plus的物理刪除和邏輯刪除使用場(chǎng)景分析,感興趣的朋友一起看看吧2021-09-09
Java使用html2image將html生成縮略圖圖片的實(shí)現(xiàn)示例
本文主要介紹了Java使用html2image將html生成縮略圖圖片的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12
十五道tomcat面試題,為數(shù)不多的機(jī)會(huì)!
這篇文章主要介紹了十五道tomcat面試題,Tomcat的本質(zhì)是一個(gè)Servlet容器。一個(gè)Servlet能做的事情是:處理請(qǐng)求資源,并為客戶端填充response對(duì)象,需要的朋友可以參考下2021-08-08
SpringMVC 接收前端傳遞的參數(shù)四種方式小結(jié)
這篇文章主要介紹了SpringMVC 接收前端傳遞的參數(shù)四種方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10

