當前位置:學者齋 >

計算機 >java語言 >

Java如何實現一個簡單的緩存

Java如何實現一個簡單的緩存

緩存是在web開發中經常用到的,將程序經常使用到或調用到的對象存在內存中,或者是耗時較長但又不具有實時性的查詢數據放入內存中,在一定程度上可以提高性能和效率。那麼,用Java如何實現一個簡單的緩存?下面本站小編帶大家一起來看看詳細內容,希望對大家有所幫助!想了解更多相關信息請持續關注我們應屆畢業生考試網!

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塊也行,都是大同小異。更高效的方法我暫時也想不出來,希望大家能多多指教。

標籤: JAVA 緩存
  • 文章版權屬於文章作者所有,轉載請註明 https://xuezhezhai.com/zh-hk/jsj/java/31jwj1.html