您的位置:首页 > 编程语言 > Java开发

java应用本地缓存

2016-08-03 21:08 295 查看
在java应用中,对于访问频率比较高,又不怎么变化的数据,常用的解决方案是把这些数据加入缓存。相比DB,缓存的读取效率快好不少。java应用缓存一般分两种,一是进程内缓存,就是使用java应用虚拟机内存的缓存;另一个是进程外缓存,现在我们常用的各种分布式缓存。相比较而言,进程内缓存比进程外缓存快很多,而且编码也简单;但是,进程内缓存的存储量有限,使用的是java应用虚拟机的内存,而且每个应用都要存储一份,有一定的资源浪费。进程外缓存相比进程内缓存,会慢些,但是,存储空间可以横向扩展,不受限制。

这里是几中场景的访问时间

-------------------------------------------------------------------
| 从数据库中读取一条数据(有索引) | 十几毫秒 |
| 从远程分布式缓存读取一条数据 | 0.5毫秒 |
| 从内存中读取1MB数据 | 十几微妙 |
-------------------------------------------------------------------

进程内缓存和进程外缓存,各有优缺点,针对不同场景,可以分别采用不同的缓存方案。对于数据量不大的,我们可以采用进程内缓存。或者只要内存足够富裕,都可以采用,但是不要盲目以为自己富裕,不然可能会导致系统内存不够。

下面要分享的是一个代码级别的,对进程内缓存的经验总结。面向jdk1.8版本。

在有效时间内缓存单个对象

public class LiveCache<T> {
// 缓存时间
private final int cacheMillis;
// 缓存对象
private final T element;
// 缓存对象创建时间
private final long createTime;

public LiveCache(int cacheMillis, T element) {
this.cacheMillis = cacheMillis;
this.element = element;
this.createTime = System.currentTimeMillis();
}

// 获取缓存对象
public T getElement() {
long currentTime = System.currentTimeMillis();
if(cacheMillis > 0 && currentTime - createTime > cacheMillis) {
return null;
} else {
return element;
}
}

// 获取缓存对象,忽略缓存时间有效性
public T getElementIfNecessary() {
return element;
}
}

public static void main(String[] args) {
int cacheMilis = 1000 ;
LiveCache<Object> liveCache = new LiveCache<>(cacheMilis, new Object()) ;

liveCache.getElement() ;
liveCache.getElementIfNecessary() ;

}


有效时间内,缓存单个对象,可异步刷新

@FunctionalInterface
public interface LiveFetch<T> {
// 刷新缓存接口
T fetch() ;
}

public class LiveManager<T> {
// 缓存时间
private int cacheMillis;
// 缓存对象
private LiveCache<T> liveCache;
// 刷新缓存的对象
private LiveFetch<T> liveFetch ;

private Logger logger = LoggerFactory.getLogger(LiveManager.class) ;

// 刷新缓存开关
private boolean refresh = false ;

public LiveManager(int cacheMillis, LiveFetch<T> liveFetch) {
this.cacheMillis = cacheMillis ;
this.liveFetch = liveFetch ;
}

/**
* fetch cache ; if cache expired , synchronous fetch
* @return
*/
public T getCache() {

initLiveCache();

if(liveCache != null) {
T t  ;
if((t= liveCache.getElement()) != null) {
return t ;
} else {
t = liveFetch.fetch() ;
if(t != null) {
liveCache = new LiveCache<T>(cacheMillis, t) ;
return t ;
}
}
}

return null ;
}

/**
* fetch cache ; if cache expired , return old cache and asynchronous fetch
* @return
*/
public T getCacheIfNecessary() {

initLiveCache();

if(liveCache != null) {
T t  ;
if((t= liveCache.getElement()) != null) {
return t ;
} else {
refreshCache() ;
return liveCache.getElementIfNecessary() ;
}
}

return null ;
}

/**
* init liveCache
*/
private void initLiveCache() {
if(liveCache == null) {
T t = liveFetch.fetch() ;
if(t != null) {
liveCache = new LiveCache<T>(cacheMillis, t) ;
}
}
}

/**
* asynchronous refresh cache
*/
private void refreshCache() {

if(refresh)
return ;
refresh = true ;
try {
Thread thread = new Thread(() -> {
try {
T t = liveFetch.fetch();
if (t != null) {
liveCache = new LiveCache<>(cacheMillis, t);
}
} catch (Exception e){
logger.error("LiveManager.refreshCache thread error.", e);
} finally {
refresh = false ;
}
}) ;
thread.start();
} catch (Exception e) {
logger.error("LiveManager.refreshCache error.", e);
}
}
}

public class Test {

public static void main(String[] args) {
int cacheMilis = 1000 ;
LiveManager<Object> liveManager = new LiveManager<>(cacheMilis,() -> new Test().t1()) ;

liveManager.getCache() ;
liveManager.getCacheIfNecessary() ;
}

public Object t1(){

return new Object() ;
}
}


有效缓存内,缓存多个对象,map结构存储,可异步刷新

@FunctionalInterface
public interface LiveMapFetch<T> {
// 异步刷新数据
T fetch(String key) ;
}

public class LiveMapManager<T> {

private int cacheMillis;
private Map<String,LiveCache<T>> liveCacheMap;
private LiveMapFetch<T> liveMapFetch;

private Logger logger = LoggerFactory.getLogger(LiveMapManager.class) ;

private boolean refresh = false ;

public LiveMapManager(int cacheMillis, LiveMapFetch<T> liveMapFetch) {
this.cacheMillis = cacheMillis ;
this.liveMapFetch = liveMapFetch ;
}

/**
* fetch cache ; if cache expired , synchronous fetch
* @return
*/
public T getCache(String key) {

initLiveCache();

T t ;
if(liveCacheMap.containsKey(key) && (t = liveCacheMap.get(key).getElement()) != null) {
return t ;
} else {
t = liveMapFetch.fetch(key) ;
if(t != null) {
LiveCache<T> liveAccess = new LiveCache<T>(cacheMillis, t) ;
liveCacheMap.put(key, liveAccess) ;
return t ;
}
}

return null ;
}

/**
* fetch cache ; if cache expired , return old cache and asynchronous fetch
* @return
*/
public T getCacheIfNecessary(String key) {

initLiveCache();

T t ;
if(liveCacheMap.containsKey(key) && (t = liveCacheMap.get(key).getElement()) != null) {
return t ;
} else {
if(liveCacheMap.containsKey(key)) {
refreshCache(key) ;
return liveCacheMap.get(key).getElementIfNecessary() ;
} else {
t = liveMapFetch.fetch(key) ;
if(t != null) {
LiveCache<T> liveAccess = new LiveCache<T>(cacheMillis, t) ;
liveCacheMap.put(key, liveAccess) ;
return t ;
}
}
}
return t ;
}

/**
* init liveCache
*/
private void initLiveCache() {
if(liveCacheMap == null) {
liveCacheMap = new HashMap<>() ;
}
}

/**
* asynchronous refresh cache
*/
private void refreshCache(String key) {

if(refresh)
return ;
refresh = true ;
try {
Thread thread = new Thread(() -> {
try {
T t = liveMapFetch.fetch(key);
if (t != null) {
LiveCache<T> liveAccess = new LiveCache<>(cacheMillis, t);
liveCacheMap.put(key, liveAccess);
}
} catch (Exception e) {
logger.error("LiveMapManager.refreshCache thread error.key:",e);
} finally {
refresh = false ;
}
}) ;
thread.start();
} catch (Exception e) {
logger.error("LiveMapManager.refreshCache error.key:" + key, e);
}
}

}

public class Test {

public static void main(String[] args) {
int cacheMilis = 1000 ;
LiveMapManager<Object> liveManager = new LiveMapManager<>(cacheMilis,(String key) -> new Test().t1(key)) ;

liveManager.getCache("key") ;
liveManager.getCacheIfNecessary("key") ;
}

public Object t1(String key){

return new Object() ;
}
}


View Code

resource : https://github.com/jxlzl1988/MyCache
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: