前言
本次分享探讨java平台的本地缓存,是指占用JVM的heap区域来缓冲存储数据的缓存组件。
一、本地缓存应用场景
localcache有着极大的性能优势:
1. 单机情况下适当使用localcache会使应用的性能得到很大的提升。
2. 集群环境下对于敏感性要求不高的数据可以使用localcache,只配置简单的失效机制来保证数据的相对一致性。
哪些数据可以存储到本地缓存?
1.访问频繁的数据;
2.静态基础数据(长时间内不变的数据);
3.相对静态数据(短时间内不变的数据)。
二、java本地缓存标准
Java缓存新标准(javax.cache),这个标准由JSR107所提出,已经被包含在Java EE 7中。
	特性:
	1.原子操作,跟java.util.ConcurrentMap类似
	2.从缓存中读取
	3.写入缓存
	4.缓存事件监听器
	5.数据统计
	6.包含所有隔离(ioslation)级别的事务
	7.缓存注解(annotations)
	8.保存定义key和值类型的泛型缓存
	9.引用保存(只适用于堆缓存)和值保存定义
但目前应用不是很普遍。
三、java开源缓存框架
比较有名的本地缓存开源框架有:
1.EHCache
EHCache是一个纯java的在进程中的缓存,它具有以下特性:快速,简单,为Hibernate2.1充当可插入的缓存,最小的依赖性,全面的文档和测试。
BUG: 过期失效的缓存元素无法被GC掉,时间越长缓存越多,内存占用越大,导致内存泄漏的概率越大。
2.OSCache
OSCache有以下特点:缓存任何对象,你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。拥有全面的API–OSCache API给你全面的程序来控制所有的OSCache特性。永久缓存–缓存能随意的写入硬盘,因此允许昂贵的创建(expensive-to-create)数据来保持缓存,甚至能让应用重启。支持集群–集群缓存数据能被单个的进行参数配置,不需要修改代码。缓存记录的过期–你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(如果默认性能不需要时)。
3.JCache
Java缓存新标准(javax.cache)
4.cache4j
cache4j是一个有简单API与实现快速的Java对象缓存。它的特性包括:在内存中进行缓存,设计用于多线程环境,两种实现:同步与阻塞,多种缓存清除策略:LFU, LRU, FIFO,可使用强引用。
5.ShiftOne
ShiftOne Java Object Cache是一个执行一系列严格的对象缓存策略的Java lib,就像一个轻量级的配置缓存工作状态的框架。
6.WhirlyCache
Whirlycache是一个快速的、可配置的、存在于内存中的对象的缓存。
四、LocalCache实现
1、LocalCache简介
LocalCache是一个精简版本地缓存组件,有以下特点:
	1. 有容量上限maxCapacity;
	2. 缓存达到容量上限时基于LRU策略来移除缓存元素;
	3. 缓存对象的生命周期(缓存失效时间)由调用方决定;
	4. 缓存对象失效后,将会有定时清理线程来清理掉,不会导致内存泄漏。
	5. 性能比Ehcache稍强。
2、总体设计
LocalCache总体设计:
	1. 缓存元素 CacheElement;
	2. 缓存容器 LRULinkedHashMap;
	3. 缓存接口 Cache;
	4. 缓存组件实现 LocalCache。
3、详细设计
1. CacheElement设计
| 
 
								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
						  | 
/**
* 缓存元素
*
*/
public class CacheElement {
private Object key;
private Object value;
private long createTime;
private long lifeTime;
private int hitCount;
public CacheElement() {
}
public CacheElement(Object key ,Object value) {
this.key = key;
this.value = value;
this.createTime = System.currentTimeMillis();
}
public Object getKey() {
return key;
}
public void setKey(Object key) {
this.key = key;
}
public Object getValue() {
hitCount++;
return value;
}
public void setValue(Object value) {
this.value = value;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public int getHitCount() {
return hitCount;
}
public void setHitCount(int hitCount) {
this.hitCount = hitCount;
}
public long getLifeTime() {
return lifeTime;
}
public void setLifeTime(long lifeTime) {
this.lifeTime = lifeTime;
}
public boolean isExpired() {
boolean isExpired = System.currentTimeMillis() - getCreateTime() > getLifeTime();
return isExpired;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[ key=").append(key).append(", isExpired=").append(isExpired())
.append(", lifeTime=").append(lifeTime).append(", createTime=").append(createTime)
.append(", hitCount=").append(hitCount)
.append(", value=").append(value).append(" ]");
return sb.toString();
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public final int hashCode(){
if(null == key){
return "".hashCode();
}
return this.key.hashCode();
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public final boolean equals(Object object) {
if ((object == null) || (!(object instanceof CacheElement))) {
return false;
}
CacheElement element = (CacheElement) object;
if ((this.key == null) || (element.getKey() == null)) {
return false;
}
return this.key.equals(element.getKey());
}
}
 | 
2. LRULinkedHashMap实现
| 
 
								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
						  | 
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 实现 LRU策略的 LinkedHashMap
*
* @param <K>
* @param <V>
*/
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> 
{ 
protected static final long serialVersionUID = 2828675280716975892L;
protected static final int DEFAULT_MAX_ENTRIES = 100;
protected final int initialCapacity; 
protected final int maxCapacity; 
protected boolean enableRemoveEldestEntry = true;//是否允许自动移除比较旧的元素(添加元素时)
protected static final float DEFAULT_LOAD_FACTOR = 0.8f; 
protected final Lock lock = new ReentrantLock(); 
public LRULinkedHashMap(int initialCapacity) 
{ 
this(initialCapacity, DEFAULT_MAX_ENTRIES);
}
public LRULinkedHashMap(int initialCapacity ,int maxCapacity) 
{ 
//set accessOrder=true, LRU
super(initialCapacity, DEFAULT_LOAD_FACTOR, true); 
this.initialCapacity = initialCapacity; 
this.maxCapacity = maxCapacity; 
}
/*
* (non-Javadoc)
* @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
*/
protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) 
{ 
return enableRemoveEldestEntry && ( size() > maxCapacity );
} 
/*
* (non-Javadoc)
* @see java.util.LinkedHashMap#get(java.lang.Object)
*/
public V get(Object key) 
{ 
try { 
lock.lock(); 
return super.get(key); 
} 
finally { 
lock.unlock(); 
} 
} 
/*
* (non-Javadoc)
* @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
*/
public V put(K key, V value) 
{ 
try { 
lock.lock(); 
return super.put(key, value); 
} 
finally { 
lock.unlock(); 
} 
} 
/*
* (non-Javadoc)
* @see java.util.HashMap#remove(java.lang.Object)
*/
public V remove(Object key) {
try { 
lock.lock();
return super.remove(key);
} 
finally { 
lock.unlock(); 
}
}
/*
* (non-Javadoc)
* @see java.util.LinkedHashMap#clear()
*/
public void clear() {
try { 
lock.lock();
super.clear();
} 
finally { 
lock.unlock();
}
}
/*
* (non-Javadoc)
* @see java.util.HashMap#keySet()
*/
public Set<K> keySet() {
try { 
lock.lock();
return super.keySet();
} 
finally { 
lock.unlock();
}
}
public boolean isEnableRemoveEldestEntry() {
return enableRemoveEldestEntry;
}
public void setEnableRemoveEldestEntry(boolean enableRemoveEldestEntry) {
this.enableRemoveEldestEntry = enableRemoveEldestEntry;
}
public int getInitialCapacity() {
return initialCapacity;
}
public int getMaxCapacity() {
return maxCapacity;
}
} 
 | 
3. Cache接口设计
| 
 
								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
						  | 
/**
* 缓存接口
*
*/
public interface Cache {
/**
* 获取缓存
* @param key
* @return
*/
public <T> T getCache(Object key);
/**
* 缓存对象
* @param key
* @param value
* @param milliSecond 缓存生命周期(毫秒)
*/
public void putCache(Object key, Object value ,Long milliSecond);
/**
* 缓存容器中是否包含 key 
* @param key
* @return
*/
public boolean containsKey(Object key);
/**
* 缓存列表大小
* @return
*/
public int getSize();
/**
* 是否启用缓存
*/
public boolean isEnabled();
/**
* 启用 或 停止
* @param enable
*/
public void setEnabled(boolean enabled);
/**
* 移除所有缓存
*/
public void invalidateCaches();
/**
* 移除 指定key缓存
* @param key
*/
public void invalidateCache(Object key);
}
 | 
4. LocalCache实现
| 
 
								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
 
								176
 
								177
 
								178
 
								179
 
								180
 
								181
 
								182
 
								183
 
								184
 
								185
 
								186
 
								187
 
								188
 
								189
 
								190
 
								191
 
								192
 
								193
 
								194
 
								195
 
								196
 
								197
 
								198
 
								199
 
								200
 
								201
 
								202
 
								203
 
								204
 
								205
 
								206
 
								207
 
								208
 
								209
 
								210
 
								211
 
								212
 
								213
 
								214
 
								215
 
								216
 
								217
 
								218
 
								219
 
								220
  | 
        