简单的java缓存实现
提到缓存,不得不提就是缓存算法(淘汰算法),常见算法有LRU、LFU和FIFO等算法,每种算法各有各的优势和缺点及适应环境。
1、LRU(Least Recently Used ,最近最少使用)
算法根据数据的最近访问记录来淘汰数据,其原理是如果数据最近被访问过,将来被访问的几概率相对比较高,最常见的实现是使用一个链表保存缓存数据,详细具体算法如下:
1. 新数据插入到链表头部;
2. 每当缓存数据命中,则将数据移到链表头部;
3. 当链表满的时候,将链表尾部的数据丢弃;
2、LFU(Least Frequently Used,最不经常使用)
算法根据数据的历史访问频率来淘汰数据,其原理是如果数据过去被访问次数越多,将来被访问的几概率相对比较高。LFU的每个数据块都有一个引用计数,所有数据块按照引用计数排序,具有相同引用计数的数据块则按照时间排序。
具体算法如下:
1. 新加入数据插入到队列尾部(因为引用计数为1);
2. 队列中的数据被访问后,引用计数增加,队列重新排序;
3. 当需要淘汰数据时,将已经排序的列表最后的数据块删除;
3、FIFO(First In First Out ,先进先出)
算法是根据先进先出原理来淘汰数据的,实现上是最简单的一种,具体算法如下:
1. 新访问的数据插入FIFO队列尾部,数据在FIFO队列中顺序移动;
2. 淘汰FIFO队列头部的数据;
评价一个缓存算法好坏的标准主要有两个,一是命中率要高,二是算法要容易实现。当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。LFU效率要优于LRU,且能够避免周期性或者偶发性的操作导致缓存命中率下降的问题。但LFU需要记录数据的历史访问记录,一旦数据访问模式改变,LFU需要更长时间来适用新的访问模式,即:LFU存在历史数据影响将来数据的“缓存污染”效用。FIFO虽然实现很简单,但是命中率很低,实际上也很少使用这种算法。
基于现有jdk类库,我们可以很容易实现上面的缓存算法
首先定义缓存接口类
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
|
/** * * * */ public
/** * * * */ int
/** * * * */ long
/** * * * * */ void
/** * * * * */ void
long
/** * * * */ V /** * * * */ int
/** * * */ boolean
/** * * * */ void
/** * */ void
/** * * * */ int
/** * */ boolean
} |
基本实现抽象类
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
import
import
import
/** * */ public
implements
class
CacheObject(K2 long
this .key this .cachedObject this .ttl this .lastAccess } final
final
long
// long
// long
// boolean
if
0 ) return
; } return
} V2 lastAccess accessCount++; return
} } protected
private
new
private
private
protected
// protected
//是否设置默认过期时间 public
return
} protected
// public
int
long
this .cacheSize this .defaultExpire } public
return
} protected
return
0
} public
put(key, } public
long
writeLock.lock(); try
CacheObject<K,V> new
if
0 ) existCustomExpire true ; } if
eliminate() } cacheMap.put(key, } finally
writeLock.unlock(); } } /** * */ public
readLock.lock(); try
CacheObject<K,V> if
null ) return
; } if
true ) cacheMap.remove(key); return
; } return
} finally
readLock.unlock(); } } public
writeLock.lock(); try
return
} finally
writeLock.unlock(); } } /** * * * */ protected
public
if
0 ) //o return
; } return
} public
writeLock.lock(); try
cacheMap.remove(key); } finally
writeLock.unlock(); } } public
writeLock.lock(); try
cacheMap.clear(); } finally
writeLock.unlock(); } } public
return
} public
return
0 ; } } |
LRU缓存实现类
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
|
import
import
import
/** * * * * * */ public
extends
public
int
long
super (cacheSize //linkedHash已经实现LRU算法 this .cacheMap new
1
true
@Override protected
Map.Entry<K, return
this .removeEldestEntry(eldest); } }; } private
if
0 ) return
; return
} /** * */ @Override protected
if (!isNeedClearExpiredObject()){ return
Iterator<CacheObject<K, int
0
while (iterator.hasNext()){ CacheObject<K, if (cacheObject.isExpired() iterator.remove(); count++ } } return
} } |
LFU实现类
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
|
import
import
//LFU实现 public
extends
public
int
long
super (cacheSize, cacheMap new
1 ) } /** * * */ @Override protected
Iterator<CacheObject<K, int
0
long
while (iterator.hasNext()){ CacheObject<K, if (cacheObject.isExpired() iterator.remove(); count++ continue
} else { minAccessCount } } if (count 0
return
if (minAccessCount iterator while (iterator.hasNext()){ CacheObject<K, cacheObject.accessCount if (cacheObject.accessCount 0
iterator.remove(); count++ } } } return
} } |
FIFO实现类
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
|
import
import
/** * * * * * */ public
extends
public
int
long
super (cacheSize, cacheMap new
1 ); } @Override protected
int
0 ; K null ; Iterator<CacheObject<K, while
CacheObject<K, if
iterator.remove(); count++; } else
if
null ) firstKey } } if
null
//删除过期对象还是满,继续删除链表第一个 cacheMap.remove(firstKey); } return
} }
|
简单的java缓存实现的更多相关文章
- 【转】简单的java缓存实现
本文转自 http://my.oschina.net/u/866190/blog/188712 提到缓存,不得不提就是缓存算法(淘汰算法),常见算法有LRU.LFU和FIFO等算法,每种算法各有各的优 ...
- 更好用 更简单的Java缓存框架 jscache
比Spring Cache 更好用 更简单的缓存工具 jscache 取名意义为 java simple cache,基于AOP实现,支持注解到接口 自定义单个缓存过期时间配置 ttl,轻松扩展缓存实 ...
- Map实现java缓存机制的简单实例
缓存是Java中主要的内容,主要目的是缓解项目访问数据库的压力以及提升访问数据的效率,以下是通过Map实现java缓存的功能,并没有用cache相关框架. 一.缓存管理类 CacheMgr.java ...
- (转)java缓存技术,记录
http://blog.csdn.net/madun/article/details/8569860 最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇 ...
- JAVA缓存技术
介绍 JNotify:http://jnotify.sourceforge.net/,通过JNI技术,让Java代码可以实时的监控制定文件夹内文件的变动信息,支持Linux/Windows/MacOS ...
- JAVA缓存技术之EhCache
最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇,暂作保存,后面如果有用到可以参考.此为转贴,帖子来处:http://cogipard.info/ar ...
- Java缓存
Java中要用到缓存的地方很多,首当其冲的就是持久层缓存,针对持久层谈一下: 要实现java缓存有很多种方式,最简单的无非就是static HashMap,这个显然是基于内存缓存,一个map就可以搞定 ...
- JAVA缓存技术之EhCache(转)
最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇,暂作保存,后面如果有用到可以参考.此为转贴,帖子来处:http://cogipard.info/ar ...
- 简单聊聊java中的final关键字
简单聊聊java中的final关键字 日常代码中,final关键字也算常用的.其主要应用在三个方面: 1)修饰类(暂时见过,但是还没用过); 2)修饰方法(见过,没写过); 3)修饰数据. 那么,我们 ...
随机推荐
- Cocos2d-x:环境配置小节
一.准备 须要下载下面内容. 1. vs2010 下载地址:http://download.microsoft.com/download/1/4/3/143B7583-6225-474F-88D5-5 ...
- contextServlet
一:读取配置文件中的参数信息 1.新建servlet文件ContextServlet1,代码为: import java.io.IOException; import java.util.Enumer ...
- o怎么样racle输入dmp数据库文件
Oracle进出口数据imp/exp等价物oracle数据恢复和备份. exp命令可以从远程数据库传输数据server出到本地的dmp文件,imp命令能够把dmp文件从本地导入到远处的数据库serve ...
- css3属性选择器总结
前两节介绍了css3属性选择器与css2属性选择器中: 包含字符串和以字符串选择器开头的选择器的比较. 全部属性选择器: 包含字符串讲解对比实例讲解链接: http://www.cnblogs.com ...
- window 7 改变窗口颜色
对于刚刚重新安装的window7系统的盆友来说,不能改变窗口的颜色,和别人的window7窗口颜色和样子不一样和不好玩,那么我教大家,如何更改窗口颜色. 首先,重装的系统用软件激活之后,肯定还没还得急 ...
- python函数abs()
详解: 返回绝对值 参数可以是:负数.正数.浮点数或者长整形 实例: abs(-1.2) #返回 1.2 abs(1.2) #返回 1.2 abs(-11216.5) #返回 11216.5 abs( ...
- [转]Swift 编程语言入门教程
今天在网上看到一篇非常好的教程,分享给大家 原文地址:http://gashero.iteye.com/blog/2075324 目录 1 简介 2 Swift入门 3 简单值 4 控 ...
- LintCode-不同的子序列
题目描述: 给出字符串S和字符串T,计算S的不同的子序列中T出现的个数. 子序列字符串是原始字符串通过删除一些(或零个)产生的一个新的字符串,并且对剩下的字符的相对位置没有影响.(比如,“ACE”是“ ...
- 转:基于node的web开发框架Express入门
JavaScript 标准参考教程(alpha) 草稿二:Node.js Express框架 GitHub TOP Express框架 来自<JavaScript 标准参考教程(alpha)&g ...
- C#)Windows Shell 编程系列5 - 获取图标
原文 C#)Windows Shell 编程系列5 - 获取图标 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 编程系列4 - 上下 ...