使用場景
在 Java
應(yīng)用中,對于訪問頻率高,更新少的數(shù)據(jù),通常的方案是將這類數(shù)據(jù)加入緩存中。相對從數(shù)據(jù)庫中讀取來說,讀緩存效率會有很大提升。
在集群環(huán)境下,常用的分布式緩存有 Redis 、 Memcached 等。但在某些業(yè)務(wù)場景上,可能不需要去搭建一套復(fù)雜的分布式緩存系統(tǒng),在單機(jī)環(huán)境下,通常是會希望使用內(nèi)部的緩存( LocalCache )。
實現(xiàn)
這里提供了兩種 LocalCache
的實現(xiàn),一種是基于 ConcurrentHashMap
實現(xiàn)基本本地緩存,另外一種是基于 LinkedHashMap
實現(xiàn) LRU
策略的本地緩存。
基于ConcurrentHashMap的實現(xiàn)
1
2
3
4
|
static { timer = new Timer(); map = new ConcurrentHashMap<>(); } |
以 ConcurrentHashMap
作為緩存的存儲結(jié)構(gòu)。因為 ConcurrentHashMap
的線程安全的,所以基于此實現(xiàn)的 LocalCache
在多線程并發(fā)環(huán)境的操作是安全的。在 JDK1.8
中, ConcurrentHashMap
是支持完全并發(fā)讀,這對本地緩存的效率也是一種提升。通過調(diào)用 ConcurrentHashMap
對 map
的操作來實現(xiàn)對緩存的操作。
私有構(gòu)造函數(shù)
1
2
3
|
privateLocalCache(){ } |
LocalCache
是工具類,通過私有構(gòu)造函數(shù)強(qiáng)化不可實例化的能力。
緩存清除機(jī)制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/** * 清除緩存任務(wù)類 */ static classCleanWorkerTaskextendsTimerTask{ private String key; publicCleanWorkerTask(String key){ this .key = key; } publicvoidrun(){ LocalCache.remove(key); } } |
清理失效緩存是由 Timer 類實現(xiàn)的。內(nèi)部類 CleanWorkerTask
繼承于 TimerTask
用戶清除緩存。每當(dāng)新增一個元素的時候,都會調(diào)用 timer.schedule 加載清除緩存的任務(wù)。
基于LinkedHashMap的實現(xiàn)
以 LinkedHashMap
作為緩存的存儲結(jié)構(gòu)。主要是通過 LinkedHashMap
的按照訪問順序的特性來實現(xiàn) LRU
策略。
LRU
LRU
是 Least Recently Used
的縮寫,即最近最久未使用。 LRU 緩存將會利用這個算法來淘汰緩存中老的數(shù)據(jù)元素,從而優(yōu)化內(nèi)存空間。
基于LRU策略的map
這里利用 LinkedHashMap
來實現(xiàn)基于 LRU
策略的 map
。通過調(diào)用父類 LinkedHashMap
的構(gòu)造函數(shù)來實例化 map
。參數(shù) accessOrder
設(shè)置為 true
保證其可以實現(xiàn) LRU
策略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
static classLRUMap<K,V>extendsLinkedHashMap<K,V>{ ... // 省略部分代碼 publicLRUMap(intinitialCapacity,floatloadFactor){ super (initialCapacity, loadFactor, true ); } ... // 省略部分代碼 /** * 重寫LinkedHashMap中removeEldestEntry方法; * 新增元素的時候,會判斷當(dāng)前map大小是否超過DEFAULT_MAX_CAPACITY,超過則移除map中最老的節(jié)點; * * @param eldest * @return */ protectedbooleanremoveEldestEntry(Map.Entry<K, V> eldest){ return size() > DEFAULT_MAX_CAPACITY; } } |
線程安全
1
2
3
4
5
6
7
8
|
/** * 讀寫鎖 */ private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final Lock rLock = readWriteLock.readLock(); private final Lock wLock = readWriteLock.writeLock(); |
LinkedHashMap
并不是線程安全,如果不加控制的在多線程環(huán)境下使用的話,會有問題。所以在 LRUMap
中引入了 ReentrantReadWriteLock
讀寫鎖,來控制并發(fā)問題。
緩存淘汰機(jī)制
1
2
3
|
protectedbooleanremoveEldestEntry(Map.Entry<K, V> eldest){ return size() > DEFAULT_MAX_CAPACITY; } |
此處重寫 LinkedHashMap
中 removeEldestEntry
方法, 當(dāng)緩存新增元素的時候,會判斷當(dāng)前 map
大小是否超過 DEFAULT_MAX_CAPACITY
,超過則移除map中最老的節(jié)點。
緩存清除機(jī)制
緩存清除機(jī)制與 ConcurrentHashMap
的實現(xiàn)一致,均是通過 timer
實現(xiàn)。
源碼地址: GitHub
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://lishuo.me/2017/05/05/Java%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98%E7%9A%84%E5%AE%9E%E7%8E%B0/?utm_source=tuicool&utm_medium=referral