緩存是在web開發中經常用到的,將程序經常使用到或調用到的對象存在內存中,或者是耗時較長但又不具有實時性的查詢數據放入內存中,在一定程度上可以提高性能和效率。下面我實現了一個簡單的緩存,步驟如下。
創建緩存對象EntityCache.java
public
class
EntityCache {
/**
* 保存的數據
*/
private
Object datas;
/**
* 設置數據失效時間,為0表示永不失效
*/
private
long
timeOut;
/**
* 最后刷新時間
*/
private
long
lastRefeshTime;
public
EntityCache(Object datas,
long
timeOut,
long
lastRefeshTime) {
this
.datas = datas;
this
.timeOut = timeOut;
this
.lastRefeshTime = lastRefeshTime;
}
public
Object getDatas() {
return
datas;
}
public
void
setDatas(Object datas) {
this
.datas = datas;
}
public
long
getTimeOut() {
return
timeOut;
}
public
void
setTimeOut(
long
timeOut) {
this
.timeOut = timeOut;
}
public
long
getLastRefeshTime() {
return
lastRefeshTime;
}
public
void
setLastRefeshTime(
long
lastRefeshTime) {
this
.lastRefeshTime = lastRefeshTime;
}
}
定義緩存操作接口,ICacheManager.java
public
interface
ICacheManager {
/**
* 存入緩存
* @param key
* @param cache
*/
void
putCache(String key, EntityCache cache);
/**
* 存入緩存
* @param key
* @param cache
*/
void
putCache(String key, Object datas,
long
timeOut);
/**
* 獲取對應緩存
* @param key
* @return
*/
EntityCache getCacheByKey(String key);
/**
* 獲取對應緩存
* @param key
* @return
*/
Object getCacheDataByKey(String key);
/**
* 獲取所有緩存
* @param key
* @return
*/
Map<String, EntityCache> getCacheAll();
/**
* 判斷是否在緩存中
* @param key
* @return
*/
boolean
isContains(String key);
/**
* 清除所有緩存
*/
void
clearAll();
/**
* 清除對應緩存
* @param key
*/
void
clearByKey(String key);
/**
* 緩存是否超時失效
* @param key
* @return
*/
boolean
isTimeOut(String key);
/**
* 獲取所有key
* @return
*/
Set<String> getAllKeys();
}
實現接口ICacheManager,CacheManagerImpl.java
這里我使用了ConcurrentHashMap來保存緩存,本來以為這樣就是線程安全的,其實不然,在后面的測試中會發現它並不是線程安全的。
public
class
CacheManagerImpl
implements
ICacheManager {
private
static
Map<String, EntityCache> caches =
new
ConcurrentHashMap<String, EntityCache>();
/**
* 存入緩存
* @param key
* @param cache
*/
public
void
putCache(String key, EntityCache cache) {
caches.put(key, cache);
}
/**
* 存入緩存
* @param key
* @param cache
*/
public
void
putCache(String key, Object datas,
long
timeOut) {
timeOut = timeOut >
0
? timeOut : 0L;
putCache(key,
new
EntityCache(datas, timeOut, System.currentTimeMillis()));
}
/**
* 獲取對應緩存
* @param key
* @return
*/
public
EntityCache getCacheByKey(String key) {
if
(
this
.isContains(key)) {
return
caches.get(key);
}
return
null
;
}
/**
* 獲取對應緩存
* @param key
* @return
*/
public
Object getCacheDataByKey(String key) {
if
(
this
.isContains(key)) {
return
caches.get(key).getDatas();
}
return
null
;
}
/**
* 獲取所有緩存
* @param key
* @return
*/
public
Map<String, EntityCache> getCacheAll() {
return
caches;
}
/**
* 判斷是否在緩存中
* @param key
* @return
*/
public
boolean
isContains(String key) {
return
caches.containsKey(key);
}
/**
* 清除所有緩存
*/
public
void
clearAll() {
caches.clear();
}
/**
* 清除對應緩存
* @param key
*/
public
void
clearByKey(String key) {
if
(
this
.isContains(key)) {
caches.remove(key);
}
}
/**
* 緩存是否超時失效
* @param key
* @return
*/
public
boolean
isTimeOut(String key) {
if
(!caches.containsKey(key)) {
return
true
;
}
EntityCache cache = caches.get(key);
long
timeOut = cache.getTimeOut();
long
lastRefreshTime = cache.getLastRefeshTime();
if
(timeOut ==
0
|| System.currentTimeMillis() - lastRefreshTime >= timeOut) {
return
true
;
}
return
false
;
}
/**
* 獲取所有key
* @return
*/
public
Set<String> getAllKeys() {
return
caches.keySet();
}
}
CacheListener.java,監聽失效數據並移除。
public
class
CacheListener{
Logger logger = Logger.getLogger(
"cacheLog"
);
private
CacheManagerImpl cacheManagerImpl;
public
CacheListener(CacheManagerImpl cacheManagerImpl) {
this
.cacheManagerImpl = cacheManagerImpl;
}
public
void
startListen() {
new
Thread(){
public
void
run() {
while
(
true
) {
for
(String key : cacheManagerImpl.getAllKeys()) {
if
(cacheManagerImpl.isTimeOut(key)) {
cacheManagerImpl.clearByKey(key);
logger.info(key +
"緩存被清除"
);
}
}
}
}
}.start();
}
}
測試類TestCache.java
public
class
TestCache {
Logger logger = Logger.getLogger(
"cacheLog"
);
/**
* 測試緩存和緩存失效
*/
@Test
public
void
testCacheManager() {
CacheManagerImpl cacheManagerImpl =
new
CacheManagerImpl();
cacheManagerImpl.putCache(
"test"
,
"test"
,
10
* 1000L);
cacheManagerImpl.putCache(
"myTest"
,
"myTest"
,
15
* 1000L);
CacheListener cacheListener =
new
CacheListener(cacheManagerImpl);
cacheListener.startListen();
logger.info(
"test:"
+ cacheManagerImpl.getCacheByKey(
"test"
).getDatas());
logger.info(
"myTest:"
+ cacheManagerImpl.getCacheByKey(
"myTest"
).getDatas());
try
{
TimeUnit.SECONDS.sleep(
20
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
logger.info(
"test:"
+ cacheManagerImpl.getCacheByKey(
"test"
));
logger.info(
"myTest:"
+ cacheManagerImpl.getCacheByKey(
"myTest"
));
}
/**
* 測試線程安全
*/
@Test
public
void
testThredSafe() {
final
String key =
"thread"
;
final
CacheManagerImpl cacheManagerImpl =
new
CacheManagerImpl();
ExecutorService exec = Executors.newCachedThreadPool();
for
(
int
i =
0
; i <
100
; i++) {
exec.execute(
new
Runnable() {
public
void
run() {
if
(!cacheManagerImpl.isContains(key)) {
cacheManagerImpl.putCache(key,
1
,
0
);
}
else
{
//因為+1和賦值操作不是原子性的,所以把它用synchronize塊包起來
synchronized
(cacheManagerImpl) {
int
value = (Integer) cacheManagerImpl.getCacheDataByKey(key) +
1
;
cacheManagerImpl.putCache(key,value ,
0
);
}
}
}
});
}
exec.shutdown();
try
{
exec.awaitTermination(
1
, TimeUnit.DAYS);
}
catch
(InterruptedException e1) {
e1.printStackTrace();
}
logger.info(cacheManagerImpl.getCacheDataByKey(key).toString());
}
}
來源:http://www.jb51.net/article/111518.htm