java应用本地缓存

 
      在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

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2016-08-03 21:08  li.zhiliang  阅读(14600)  评论(0编辑  收藏  举报