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

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM