Java如何實現一個簡單的緩存
- java語言
- 關注:1.08W次
緩存是在web開發中經常用到的,將程序經常使用到或調用到的對象存在內存中,或者是耗時較長但又不具有實時性的查詢數據放入內存中,在一定程度上可以提高性能和效率。那麼,用Java如何實現一個簡單的緩存?下面本站小編帶大家一起來看看詳細內容,希望對大家有所幫助!想了解更多相關信息請持續關注我們應屆畢業生考試網!
創建緩存對象
public class EntityCache {
/**
* 保存的數據
*/
private Object datas;
/**
* 設置數據失效時間,為0表示永不失效
*/
private long timeOut;
/**
* 最後刷新時間
*/
private long lastRefeshTime;
public EntityCache(Object datas, long timeOut, long lastRefeshTime) {
s = datas;
Out = timeOut;
RefeshTime = lastRefeshTime;
}
public Object getDatas() {
return datas;
}
public void setDatas(Object datas) {
s = datas;
}
public long getTimeOut() {
return timeOut;
}
public void setTimeOut(long timeOut) {
Out = timeOut;
}
public long getLastRefeshTime() {
return lastRefeshTime;
}
public void setLastRefeshTime(long lastRefeshTime) {
RefeshTime = lastRefeshTime;
}
}
定義緩存操作接口,
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,
這裏我使用了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) {
(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, entTimeMillis()));
}
/**
* 獲取對應緩存
* @param key
* @return
*/
public EntityCache getCacheByKey(String key) {
if (ntains(key)) {
return (key);
}
return null;
}
/**
* 獲取對應緩存
* @param key
* @return
*/
public Object getCacheDataByKey(String key) {
if (ntains(key)) {
return (key)atas();
}
return null;
}
/**
* 獲取所有緩存
* @param key
* @return
*/
public Map<String, EntityCache> getCacheAll() {
return caches;
}
/**
* 判斷是否在緩存中
* @param key
* @return
*/
public boolean isContains(String key) {
return ainsKey(key);
}
/**
* 清除所有緩存
*/
public void clearAll() {
r();
}
/**
* 清除對應緩存
* @param key
*/
public void clearByKey(String key) {
if (ntains(key)) {
ve(key);
}
}
/**
* 緩存是否超時失效
* @param key
* @return
*/
public boolean isTimeOut(String key) {
if (!ainsKey(key)) {
return true;
}
EntityCache cache = (key);
long timeOut = imeOut();
long lastRefreshTime = astRefeshTime();
if (timeOut == 0 || entTimeMillis() - lastRefreshTime >= timeOut) {
return true;
}
return false;
}
/**
* 獲取所有key
* @return
*/
public Set<String> getAllKeys() {
return et();
}
}
,監聽失效數據並移除。
public class CacheListener{
Logger logger = ogger("cacheLog");
private CacheManagerImpl cacheManagerImpl;
public CacheListener(CacheManagerImpl cacheManagerImpl) {
eManagerImpl = cacheManagerImpl;
}
public void startListen() {
new Thread(){
public void run() {
while (true) {
for(String key : llKeys()) {
if (meOut(key)) {
rByKey(key);
(key + "緩存被清除");
}
}
}
}
}t();
}
}
測試類
public class TestCache {
Logger logger = ogger("cacheLog");
/**
* 測試緩存和緩存失效
*/
@Test
public void testCacheManager() {
CacheManagerImpl cacheManagerImpl = new CacheManagerImpl();
ache("test", "test", 10 * 1000L);
ache("myTest", "myTest", 15 * 1000L);
CacheListener cacheListener = new CacheListener(cacheManagerImpl);
tListen();
("test:" + acheByKey("test")atas());
("myTest:" + acheByKey("myTest")atas());
try {
p(20);
} catch (InterruptedException e) {
tStackTrace();
}
("test:" + acheByKey("test"));
("myTest:" + acheByKey("myTest"));
}
/**
* 測試線程安全
*/
@Test
public void testThredSafe() {
final String key = "thread";
final CacheManagerImpl cacheManagerImpl = new CacheManagerImpl();
ExecutorService exec = achedThreadPool();
for (int i = 0; i < 100; i++) {
ute(new Runnable() {
public void run() {
if (!ntains(key)) {
ache(key, 1, 0);
} else {
//因為+1和賦值操作不是原子性的,所以把它用synchronize塊包起來
synchronized (cacheManagerImpl) {
int value = (Integer) acheDataByKey(key) + 1;
ache(key,value , 0);
}
}
}
});
}
down();
try {
tTermination(1, );
} catch (InterruptedException e1) {
tStackTrace();
}
(acheDataByKey(key)ring());
}
}
testCacheManager()輸出結果如下:
2017-4-17 10:33:51 Cache testCacheManager
信息: test:test
2017-4-17 10:33:51 Cache testCacheManager
信息: myTest:myTest
2017-4-17 10:34:01 eListener$1 run
信息: test緩存被清除
2017-4-17 10:34:06 eListener$1 run
信息: myTest緩存被清除
2017-4-17 10:34:11 Cache testCacheManager
信息: test:null
2017-4-17 10:34:11 Cache testCacheManager
信息: myTest:null
testThredSafe()輸出結果如下(選出了各種結果中的一個舉例):
2017-4-17 10:35:36 Cache testThredSafe
信息: 96
可以看到並不是預期的結果100,為什麼呢?ConcurrentHashMap只能保證單次操作的原子性,但是當複合使用的時候,沒辦法保證複合操作的'原子性,以下代碼:
if (!ntains(key)) {
ache(key, 1, 0);
}
多線程的時候回重複更新value,設置為1,所以出現結果不是預期的100。所以辦法就是在中都加上synchronized,但是這樣一來相當於操作都是串行,使用ConcurrentHashMap也沒有什麼意義,不過只是簡單的緩存還是可以的。或者對測試方法中的run裏面加上synchronized塊也行,都是大同小異。更高效的方法我暫時也想不出來,希望大家能多多指教。
- 文章版權屬於文章作者所有,轉載請註明 https://xuezhezhai.com/zh-hk/jsj/java/31jwj1.html