缓存框架OSCache部分源码分析
来源:互联网 发布:linux 安装不了vnc 编辑:程序博客网 时间:2024/06/05 18:36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//从缓存中获取指定key对应的内容
public
Object getFromCache(String key,
int
refreshPeriod, String cronExpiry)
throws
NeedsRefreshException {
//首先尝试获取内容,如果获取不到,则新建一个CacheEntry对象
CacheEntry cacheEntry =
this
.getCacheEntry(key,
null
,
null
);
Object content = cacheEntry.getContent();
CacheMapAccessEventType accessEventType = CacheMapAccessEventType.HIT;
boolean
reload =
false
;
// 检查缓存是否过期,如果过期分为以下几种情况处理
if
(
this
.isStale(cacheEntry, refreshPeriod, cronExpiry)) {
//获取更新状态,如果没有,新建一个同时引用计数默认为1
EntryUpdateState updateState = getUpdateState(key);
try
{
synchronized
(updateState) {
if
(updateState.isAwaitingUpdate() || updateState.isCancelled()) {
// 如果状态为等待刷新或者已经取消刷新,说明当前没有其他线程对其进行刷新操作
// 因此这里启动刷新操作(这里会将状态更新为刷新中同时引用计数+1)
updateState.startUpdate();
//如果是新建的CacheEntry对象(即之前未缓存该key对应的对象)
if
(cacheEntry.isNew()) {
//设置命中状态为未命中
accessEventType = CacheMapAccessEventType.MISS;
}
else
{
//否则说明虽然命中了,但是需要刷新
accessEventType = CacheMapAccessEventType.STALE_HIT;
}
}
else
if
(updateState.isUpdating()) {
// 如果更新状态为刷新中,说明另有一个线程正对该缓存对象执行刷新操作
// 此时如果是新建的CacheEntry对象或者同步模式设置为true,那么该线程将阻塞
//通过putInCache或者cancelUpdate可以让线程继续运行
// 否则获取到的很有可能是脏数据
if
(cacheEntry.isNew() || blocking) {
do
{
try
{
updateState.wait();
}
catch
(InterruptedException e) {
}
}
while
(updateState.isUpdating());
//如果更新状态变成了取消,说明另外一个线程取消了刷新缓存操作,那么让该线程尝试刷新
if
(updateState.isCancelled()) {
//更新状态设置为更新中并将引用计数+1
updateState.startUpdate();
if
(cacheEntry.isNew()) {
accessEventType = CacheMapAccessEventType.MISS;
}
else
{
accessEventType = CacheMapAccessEventType.STALE_HIT;
}
}
else
if
(updateState.isComplete()) {
reload =
true
;
}
else
{
log.error(
"Invalid update state for cache entry "
+ key);
}
}
}
else
{
reload =
true
;
}
}
}
finally
{
//将引用计数-1同时检查如果引用计数=0,将updateState移除
releaseUpdateState(updateState, key);
}
}
// 如果该标志位为true,说明缓存一定刷新了
if
(reload) {
cacheEntry = (CacheEntry) cacheMap.get(key);
if
(cacheEntry !=
null
) {
content = cacheEntry.getContent();
}
else
{
log.error(
"Could not reload cache entry after waiting for it to be rebuilt"
);
}
}
dispatchCacheMapAccessEvent(accessEventType, cacheEntry,
null
);
// 如果缓存不存在或者缓存过期将抛出需要刷新的异常
if
(accessEventType != CacheMapAccessEventType.HIT) {
throw
new
NeedsRefreshException(content);
}
return
content;
}
1
2
3
4
5
6
7
8
9
10
11
12
//默认
public
static
final
int
NOT_YET_UPDATING = -
1
;
public
static
final
int
UPDATE_IN_PROGRESS =
0
;
public
static
final
int
UPDATE_COMPLETE =
1
;
public
static
final
int
UPDATE_CANCELLED =
2
;
int
state = NOT_YET_UPDATING;
//引用计数
private
int
nbConcurrentUses =
1
;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//第一种:with fail over
String myKey =
"myKey"
;
String myValue;
int
myRefreshPeriod =
1000
;
try
{
// Get from the cache
myValue = (String) admin.getFromCache(myKey, myRefreshPeriod);
}
catch
(NeedsRefreshException nre) {
try
{
// Get the value (probably by calling an EJB)
myValue =
"This is the content retrieved."
;
// Store in the cache
admin.putInCache(myKey, myValue);
}
catch
(Exception ex) {
// We have the current content if we want fail-over.
myValue = (String) nre.getCacheContent();
// It is essential that cancelUpdate is called if the
// cached content is not rebuilt
admin.cancelUpdate(myKey);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//第二种:without fail over
String myKey =
"myKey"
;
String myValue;
int
myRefreshPeriod =
1000
;
try
{
// Get from the cache
myValue = (String) admin.getFromCache(myKey, myRefreshPeriod);
}
catch
(NeedsRefreshException nre) {
try
{
// Get the value (probably by calling an EJB)
myValue =
"This is the content retrieved."
;
// Store in the cache
admin.putInCache(myKey, myValue);
updated =
true
;
}
finally
{
if
(!updated) {
// It is essential that cancelUpdate is called if the
// cached content could not be rebuilt
admin.cancelUpdate(myKey);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public
void
putInCache(String key, Object content, String[] groups, EntryRefreshPolicy policy, String origin) {
CacheEntry cacheEntry =
this
.getCacheEntry(key, policy, origin);
boolean
isNewEntry = cacheEntry.isNew();
// 首先判断缓存中是否已经存在
if
(!isNewEntry) {
cacheEntry =
new
CacheEntry(key, policy);
}
cacheEntry.setContent(content);
cacheEntry.setGroups(groups);
cacheMap.put(key, cacheEntry);
// 更新状态及引用计数,通知其它阻塞线程可以获取缓存了
completeUpdate(key);
//......
//......
}
}
protected
void
completeUpdate(String key) {
EntryUpdateState state;
synchronized
(updateStates) {
state = (EntryUpdateState) updateStates.get(key);
if
(state !=
null
) {
synchronized
(state) {
//更新状态为UPDATE_COMPLETE,引用计数-1
int
usageCounter = state.completeUpdate();
//唤醒其它等待该缓存资源的线程
state.notifyAll();
checkEntryStateUpdateUsage(key, state, usageCounter);
}
}
else
{
//如果putInCache方法直接调用(如不是因NeedRefreshException异常调用)这样EntryUpdateState将为null,不执行操作
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public
void
cancelUpdate(String key) {
EntryUpdateState state;
if
(key !=
null
) {
synchronized
(updateStates) {
state = (EntryUpdateState) updateStates.get(key);
if
(state !=
null
) {
synchronized
(state) {
//更新状态为UPDATE_CANCELLED,引用计数-1
int
usageCounter = state.cancelUpdate();
state.notify();
checkEntryStateUpdateUsage(key, state, usageCounter);
}
}
else
{
if
(log.isErrorEnabled()) {
log.error(
"internal error: expected to get a state from key ["
+ key +
"]"
);
}
}
}
}
}
Least Frequently Used(LFU):计算每个缓存对象的使用频率,将频率最低的剔除;
Least Recently User(LRU):最近最少使用,具体是将最近访问的内容始终放在最顶端,一直未访问或者最久未访问的内容放在最底端,当需要替换的时候,只需将最底端的剔除即可,这样可以使得最常访问的内容始终在缓存中,使用比较广泛,OSCache中默认也是采用该方法。LRU的这种特性,在Java中很容易通过LinkedHashMap实现,具体实现方法可以参考下面的介绍。
First in First out(FIFO):先进先出。实现起来最为简单,但是不适用。
Random Cache:随机替换。
1
final
boolean
accessOrder;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public
LinkedHashMap(
int
initialCapacity,
float
loadFactor) {
super
(initialCapacity, loadFactor);
accessOrder =
false
;
}
public
LinkedHashMap(
int
initialCapacity) {
super
(initialCapacity);
accessOrder =
false
;
}
public
LinkedHashMap() {
super
();
accessOrder =
false
;
}
public
LinkedHashMap(Map<?
extends
K, ?
extends
V> m) {
super
();
accessOrder =
false
;
putMapEntries(m,
false
);
}
public
LinkedHashMap(
int
initialCapacity,
float
loadFactor,
boolean
accessOrder) {
super
(initialCapacity, loadFactor);
this
.accessOrder = accessOrder;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void
afterNodeInsertion(
boolean
evict) {
// possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if
(evict && (first = head) !=
null
&& removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key,
null
,
false
,
true
);
}
}
/**
* Returns <tt>true</tt> if this map should remove its eldest entry.
* This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
* inserting a new entry into the map. It provides the implementor
* with the opportunity to remove the eldest entry each time a new one
* is added. This is useful if the map represents a cache: it allows
* the map to reduce memory consumption by deleting stale entries.
*
* <p>Sample use: this override will allow the map to grow up to 100
* entries and then delete the eldest entry each time a new entry is
* added, maintaining a steady state of 100 entries.
* <pre>
* private static final int MAX_ENTRIES = 100;
*
* protected boolean removeEldestEntry(Map.Entry eldest) {
* return size() > MAX_ENTRIES;
* }
* </pre>
*
* <p>This method typically does not modify the map in any way,
* instead allowing the map to modify itself as directed by its
* return value. It <i>is</i> permitted for this method to modify
* the map directly, but if it does so, it <i>must</i> return
* <tt>false</tt> (indicating that the map should not attempt any
* further modification). The effects of returning <tt>true</tt>
* after modifying the map from within this method are unspecified.
*
* <p>This implementation merely returns <tt>false</tt> (so that this
* map acts like a normal map - the eldest element is never removed).
*
* @param eldest The least recently inserted entry in the map, or if
* this is an access-ordered map, the least recently accessed
* entry. This is the entry that will be removed it this
* method returns <tt>true</tt>. If the map was empty prior
* to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
* in this invocation, this will be the entry that was just
* inserted; in other words, if the map contains a single
* entry, the eldest entry is also the newest.
* @return <tt>true</tt> if the eldest entry should be removed
* from the map; <tt>false</tt> if it should be retained.
*/
protected
boolean
removeEldestEntry(Map.Entry<K,V> eldest) {
return
false
;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import
java.util.LinkedHashMap;
import
java.util.Collection;
import
java.util.Map;
import
java.util.ArrayList;
/**
* An LRU cache, based on <code>LinkedHashMap</code>.
*
* <p>
* This cache has a fixed maximum number of elements (<code>cacheSize</code>).
* If the cache is full and another entry is added, the LRU (least recently
* used) entry is dropped.
*
* <p>
* This class is thread-safe. All methods of this class are synchronized.
*
* <p>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / GPL / AL / BSD.
*/
public
class
LRUCache<K, V> {
private
static
final
float
hashTableLoadFactor =
0
.75f;
private
LinkedHashMap<K, V> map;
private
int
cacheSize;
/**
* Creates a new LRU cache. 在该方法中,new LinkedHashMap<K,V>(hashTableCapacity,
* hashTableLoadFactor, true)中,true代表使用访问顺序
*
* @param cacheSize
* the maximum number of entries that will be kept in this cache.
*/
public
LRUCache(
int
cacheSize) {
this
.cacheSize = cacheSize;
int
hashTableCapacity = (
int
) Math
.ceil(cacheSize / hashTableLoadFactor) +
1
;
map =
new
LinkedHashMap<K, V>(hashTableCapacity, hashTableLoadFactor,
true
) {
// (an anonymous inner class)
private
static
final
long
serialVersionUID =
1
;
@Override
protected
boolean
removeEldestEntry(Map.Entry<K, V> eldest) {
return
size() > LRUCache.
this
.cacheSize;
}
};
}
/**
* Retrieves an entry from the cache.<br>
* The retrieved entry becomes the MRU (most recently used) entry.
*
* @param key
* the key whose associated value is to be returned.
* @return the value associated to this key, or null if no value with this
* key exists in the cache.
*/
public
synchronized
V get(K key) {
return
map.get(key);
}
/**
* Adds an entry to this cache. The new entry becomes the MRU (most recently
* used) entry. If an entry with the specified key already exists in the
* cache, it is replaced by the new entry. If the cache is full, the LRU
* (least recently used) entry is removed from the cache.
*
* @param key
* the key with which the specified value is to be associated.
* @param value
* a value to be associated with the specified key.
*/
public
synchronized
void
put(K key, V value) {
map.put(key, value);
}
/**
* Clears the cache.
*/
public
synchronized
void
clear() {
map.clear();
}
/**
* Returns the number of used entries in the cache.
*
* @return the number of entries currently in the cache.
*/
public
synchronized
int
usedEntries() {
return
map.size();
}
/**
* Returns a <code>Collection</code> that contains a copy of all cache
* entries.
*
* @return a <code>Collection</code> with a copy of the cache content.
*/
public
synchronized
Collection<Map.Entry<K, V>> getAll() {
return
new
ArrayList<Map.Entry<K, V>>(map.entrySet());
}
}
0 0
- 缓存框架OSCache部分源码分析
- 缓存框架OSCache部分源码分析
- 缓存框架OSCache部分源码分析
- 缓存框架Guava Cache部分源码分析
- OSCache缓存框架介绍
- OSCache缓存框架学习
- OSCache缓存框架的简单用法
- OSCache 缓存框架 及错误点
- OSCache缓存
- OSCache缓存
- osCache缓存
- 首选项框架PreferenceFragment部分源码分析
- Phalcon框架启动流程(部分源码)分析
- android缓存框架ASimpleCache源码分析
- 缓存框架 ASimpleCache 源码分析地址收藏
- 关于缓存框架oscache的几点总结
- Java开源缓存框架 oscache下载、介绍使用
- 几个著名Java开源缓存框架介绍(OSCache,JSC)
- Hausdorff distance的模板匹配
- opencv 图像的轮廓查找 滚动条函数设置查找轮廓
- CSU - 1213 二叉树结点公共祖先
- 在虚拟机中安装linux后切换至图形界面
- Cannot reload AVD list: cvc-enumeration-valid: Value '360dpi' is...
- 缓存框架OSCache部分源码分析
- tomcat 配置jmx远程监控
- 性能测试结果分析
- Xml解析
- java设计模式进阶_interpreter
- MyEclipse10手动安装Jad反编译
- 【洛谷 1168】中位数
- Activity 和 Fragment 生命周期 图形说明
- 邻接表 图的存储结构