国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Guava學(xué)習(xí):Cache緩存入門

xingpingz / 2402人閱讀

摘要:并且添加了監(jiān)聽器,當(dāng)數(shù)據(jù)被刪除后會打印日志。六總結(jié)回顧緩存加載顯示插入緩存回收,定時,,軟弱引用,顯示刪除接口方法,監(jiān)聽器清理緩存時間只有在獲取數(shù)據(jù)時才或清理緩存,使用者可以單起線程采用方法主動清理。

摘要: 學(xué)習(xí)Google內(nèi)部使用的工具包Guava,在Java項目中輕松地增加緩存,提高程序獲取數(shù)據(jù)的效率。
一、什么是緩存?

根據(jù)科普中國的定義,緩存就是數(shù)據(jù)交換的緩沖區(qū)(稱作Cache),當(dāng)某一硬件要讀取數(shù)據(jù)時,會首先從緩存中查找需要的數(shù)據(jù),如果找到了則直接執(zhí)行,找不到的話則從內(nèi)存中找。由于緩存的運行速度比內(nèi)存快得多,故緩存的作用就是幫助硬件更快地運行。

在這里,我們借用了硬件緩存的概念,當(dāng)在Java程序中計算或查詢數(shù)據(jù)的代價很高,并且對同樣的計算或查詢條件需要不止一次獲取數(shù)據(jù)的時候,就應(yīng)當(dāng)考慮使用緩存。換句話說,緩存就是以空間換時間,大部分應(yīng)用在各種IO,數(shù)據(jù)庫查詢等耗時較長的應(yīng)用當(dāng)中。

二、緩存原理

當(dāng)獲取數(shù)據(jù)時,程序?qū)⑾葟囊粋€存儲在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)中獲取數(shù)據(jù)。如果數(shù)據(jù)不存在,則在磁盤或者數(shù)據(jù)庫中獲取數(shù)據(jù)并存入到數(shù)據(jù)結(jié)構(gòu)當(dāng)中。之后程序需要再次獲取數(shù)據(jù)時,則會先查詢這個數(shù)據(jù)結(jié)構(gòu)。從內(nèi)存中獲取數(shù)據(jù)時間明顯小于通過IO獲取數(shù)據(jù),這個數(shù)據(jù)結(jié)構(gòu)就是緩存的實現(xiàn)。

這里引入一個概念,緩存命中率:從緩存中獲取到數(shù)據(jù)的次數(shù)/全部查詢次數(shù),命中率越高說明這個緩存的效率好。由于機(jī)器內(nèi)存的限制,緩存一般只能占據(jù)有限的內(nèi)存大小,緩存需要不定期的刪除一部分?jǐn)?shù)據(jù),從而保證不會占據(jù)大量內(nèi)存導(dǎo)致機(jī)器崩潰。

如何提高命中率呢?那就得從刪除一部分?jǐn)?shù)據(jù)著手了。目前有三種刪除數(shù)據(jù)的方式,分別是:FIFO(先進(jìn)先出)LFU(定期淘汰最少使用次數(shù))LRU(淘汰最長時間未被使用)

三、GuavaCache工作方式

GuavaCache的工作流程獲取數(shù)據(jù)->如果存在,返回數(shù)據(jù)->計算獲取數(shù)據(jù)->存儲返回。由于特定的工作流程,使用者必須在創(chuàng)建Cache或者獲取數(shù)據(jù)時指定不存在數(shù)據(jù)時應(yīng)當(dāng)怎么獲取數(shù)據(jù)。GuavaCache采用LRU的工作原理,使用者必須指定緩存數(shù)據(jù)的大小,當(dāng)超過緩存大小時,必定引發(fā)數(shù)據(jù)刪除。GuavaCache還可以讓用戶指定緩存數(shù)據(jù)的過期時間,刷新時間等等很多有用的功能。

四、GuavaCache使用Demo 4.1 簡單使用

有人說我就想簡簡單單的使用cache,就像Map那樣方便就行。接下來展示一段簡單的使用方式。

首先定義一個需要存儲的Bean,對象Man:

/**
 * @author jiangmitiao
 * @version V1.0
 * @Title: 標(biāo)題
 * @Description: Bean
 * @date 2016/10/27 10:01
 */
public class Man {
    //身份證號
    private String id;
    //姓名
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Man{" +
                "id="" + id + """ +
                ", name="" + name + """ +
                "}";
    }
}

接下來我們寫一個Demo:

import com.google.common.cache.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;


/**
 * @author jiangmitiao
 * @version V1.0
 * @Description: Demo
 * @date 2016/10/27 10:00
 */
public class GuavaCachDemo {
    private LoadingCache loadingCache;

    //loadingCache
    public void InitLoadingCache() {
        //指定一個如果數(shù)據(jù)不存在獲取數(shù)據(jù)的方法
        CacheLoader cacheLoader = new CacheLoader() {
            @Override
            public Man load(String key) throws Exception {
                //模擬mysql操作
                Logger logger = LoggerFactory.getLogger("LoadingCache");
                logger.info("LoadingCache測試 從mysql加載緩存ing...(2s)");
                Thread.sleep(2000);
                logger.info("LoadingCache測試 從mysql加載緩存成功");
                Man tmpman = new Man();
                tmpman.setId(key);
                tmpman.setName("其他人");
                if (key.equals("001")) {
                    tmpman.setName("張三");
                    return tmpman;
                }
                if (key.equals("002")) {
                    tmpman.setName("李四");
                    return tmpman;
                }
                return tmpman;
            }
        };
        //緩存數(shù)量為1,為了展示緩存刪除效果
        loadingCache = CacheBuilder.newBuilder().maximumSize(1).build(cacheLoader);
    }
    //獲取數(shù)據(jù),如果不存在返回null
    public Man getIfPresentloadingCache(String key){
        return loadingCache.getIfPresent(key);
    }
    //獲取數(shù)據(jù),如果數(shù)據(jù)不存在則通過cacheLoader獲取數(shù)據(jù),緩存并返回
    public Man getCacheKeyloadingCache(String key){
        try {
            return loadingCache.get(key);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
    //直接向緩存put數(shù)據(jù)
    public void putloadingCache(String key,Man value){
        Logger logger = LoggerFactory.getLogger("LoadingCache");
        logger.info("put key :{} value : {}",key,value.getName());
        loadingCache.put(key,value);
    }
}

接下來,我們寫一些測試方法,檢測一下

public class Test {
    public static void main(String[] args){
        GuavaCachDemo cachDemo = new GuavaCachDemo()
        System.out.println("使用loadingCache");
        cachDemo.InitLoadingCache();

        System.out.println("使用loadingCache get方法  第一次加載");
        Man man = cachDemo.getCacheKeyloadingCache("001");
        System.out.println(man);

        System.out.println("
使用loadingCache getIfPresent方法  第一次加載");
        man = cachDemo.getIfPresentloadingCache("002");
        System.out.println(man);

        System.out.println("
使用loadingCache get方法  第一次加載");
        man = cachDemo.getCacheKeyloadingCache("002");
        System.out.println(man);

        System.out.println("
使用loadingCache get方法  已加載過");
        man = cachDemo.getCacheKeyloadingCache("002");
        System.out.println(man);

        System.out.println("
使用loadingCache get方法  已加載過,但是已經(jīng)被剔除掉,驗證重新加載");
        man = cachDemo.getCacheKeyloadingCache("001");
        System.out.println(man);

        System.out.println("
使用loadingCache getIfPresent方法  已加載過");
        man = cachDemo.getIfPresentloadingCache("001");
        System.out.println(man);

        System.out.println("
使用loadingCache put方法  再次get");
        Man newMan = new Man();
        newMan.setId("001");
        newMan.setName("額外添加");
        cachDemo.putloadingCache("001",newMan);
        man = cachDemo.getCacheKeyloadingCache("001");
        System.out.println(man);
    }
}

測試結(jié)果如下:

4.2 高級特性
由于目前使用有局限性,接下來只講我用到的一些方法。

我來演示一下GuavaCache自帶的兩個Cache

GuavaCacheDemo.java

import com.google.common.cache.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;


/**
 * @author jiangmitiao
 * @version V1.0
 * @Description: Demo
 * @date 2016/10/27 10:00
 */
public class GuavaCachDemo {
    private Cache cache;
    private LoadingCache loadingCache;
    private RemovalListener removalListener;

    public void Init(){
        //移除key-value監(jiān)聽器
        removalListener = new RemovalListener(){
            public void onRemoval(RemovalNotification notification) {
                Logger logger = LoggerFactory.getLogger("RemovalListener");
                logger.info(notification.getKey()+"被移除");
                //可以在監(jiān)聽器中獲取key,value,和刪除原因
                notification.getValue();
                notification.getCause();//EXPLICIT、REPLACED、COLLECTED、EXPIRED、SIZE

            }};
        //可以使用RemovalListeners.asynchronous方法將移除監(jiān)聽器設(shè)為異步方法
        //removalListener = RemovalListeners.asynchronous(removalListener, new ThreadPoolExecutor(1,1,1000, TimeUnit.MINUTES,new ArrayBlockingQueue(1)));
    }

    //loadingCache
    public void InitLoadingCache() {
        //指定一個如果數(shù)據(jù)不存在獲取數(shù)據(jù)的方法
        CacheLoader cacheLoader = new CacheLoader() {
            @Override
            public Man load(String key) throws Exception {
                //模擬mysql操作
                Logger logger = LoggerFactory.getLogger("LoadingCache");
                logger.info("LoadingCache測試 從mysql加載緩存ing...(2s)");
                Thread.sleep(2000);
                logger.info("LoadingCache測試 從mysql加載緩存成功");
                Man tmpman = new Man();
                tmpman.setId(key);
                tmpman.setName("其他人");
                if (key.equals("001")) {
                    tmpman.setName("張三");
                    return tmpman;
                }
                if (key.equals("002")) {
                    tmpman.setName("李四");
                    return tmpman;
                }
                return tmpman;
            }
        };
        //緩存數(shù)量為1,為了展示緩存刪除效果
        loadingCache = CacheBuilder.newBuilder().
                //設(shè)置2分鐘沒有獲取將會移除數(shù)據(jù)
                expireAfterAccess(2, TimeUnit.MINUTES).
                //設(shè)置2分鐘沒有更新數(shù)據(jù)則會移除數(shù)據(jù)
                expireAfterWrite(2, TimeUnit.MINUTES).
                //每1分鐘刷新數(shù)據(jù)
                refreshAfterWrite(1,TimeUnit.MINUTES).
                //設(shè)置key為弱引用
                weakKeys().
//                weakValues().//設(shè)置存在時間和刷新時間后不能再次設(shè)置
//                softValues().//設(shè)置存在時間和刷新時間后不能再次設(shè)置
                maximumSize(1).
                removalListener(removalListener).
                build(cacheLoader);
    }

    //獲取數(shù)據(jù),如果不存在返回null
    public Man getIfPresentloadingCache(String key){
        return loadingCache.getIfPresent(key);
    }

    //獲取數(shù)據(jù),如果數(shù)據(jù)不存在則通過cacheLoader獲取數(shù)據(jù),緩存并返回
    public Man getCacheKeyloadingCache(String key){
        try {
            return loadingCache.get(key);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }

    //直接向緩存put數(shù)據(jù)
    public void putloadingCache(String key,Man value){
        Logger logger = LoggerFactory.getLogger("LoadingCache");
        logger.info("put key :{} value : {}",key,value.getName());
        loadingCache.put(key,value);
    }

    public void InitDefault() {
        cache = CacheBuilder.newBuilder().
                expireAfterAccess(2, TimeUnit.MINUTES).
                expireAfterWrite(2, TimeUnit.MINUTES).
//                refreshAfterWrite(1,TimeUnit.MINUTES).//沒有cacheLoader的cache不能設(shè)置刷新,因為沒有指定獲取數(shù)據(jù)的方式
                weakKeys().
//                weakValues().//設(shè)置存在時間和刷新時間后不能再次設(shè)置
//                softValues().//設(shè)置存在時間和刷新時間后不能再次設(shè)置
                maximumSize(1).
                removalListener(removalListener).
                build();
    }

    public Man getIfPresentCache(String key){
        return cache.getIfPresent(key);
    }
    public Man getCacheKeyCache(final String key) throws ExecutionException {
        return cache.get(key, new Callable() {
            public Man call() throws Exception {
                //模擬mysql操作
                Logger logger = LoggerFactory.getLogger("Cache");
                logger.info("Cache測試 從mysql加載緩存ing...(2s)");
                Thread.sleep(2000);
                logger.info("Cache測試 從mysql加載緩存成功");
                Man tmpman = new Man();
                tmpman.setId(key);
                tmpman.setName("其他人");
                if (key.equals("001")) {
                    tmpman.setName("張三");
                    return tmpman;
                }
                if (key.equals("002")) {
                    tmpman.setName("李四");
                    return tmpman;
                }
                return tmpman;
            }
        });
    }

    public void putCache(String key,Man value){
        Logger logger = LoggerFactory.getLogger("Cache");
        logger.info("put key :{} value : {}",key,value.getName());
        cache.put(key,value);
    }
}

在這個demo中,分別采用了Guava自帶的兩個Cache:LocalLoadingCache和LocalManualCache。并且添加了監(jiān)聽器,當(dāng)數(shù)據(jù)被刪除后會打印日志。

Main:

public static void main(String[] args){
    GuavaCachDemo cachDemo = new GuavaCachDemo();
    cachDemo.Init();

    System.out.println("使用loadingCache");
    cachDemo.InitLoadingCache();

    System.out.println("使用loadingCache get方法  第一次加載");
    Man man = cachDemo.getCacheKeyloadingCache("001");
    System.out.println(man);

    System.out.println("
使用loadingCache getIfPresent方法  第一次加載");
    man = cachDemo.getIfPresentloadingCache("002");
    System.out.println(man);

    System.out.println("
使用loadingCache get方法  第一次加載");
    man = cachDemo.getCacheKeyloadingCache("002");
    System.out.println(man);

    System.out.println("
使用loadingCache get方法  已加載過");
    man = cachDemo.getCacheKeyloadingCache("002");
    System.out.println(man);

    System.out.println("
使用loadingCache get方法  已加載過,但是已經(jīng)被剔除掉,驗證重新加載");
    man = cachDemo.getCacheKeyloadingCache("001");
    System.out.println(man);

    System.out.println("
使用loadingCache getIfPresent方法  已加載過");
    man = cachDemo.getIfPresentloadingCache("001");
    System.out.println(man);

    System.out.println("
使用loadingCache put方法  再次get");
    Man newMan = new Man();
    newMan.setId("001");
    newMan.setName("額外添加");
    cachDemo.putloadingCache("001",newMan);
    man = cachDemo.getCacheKeyloadingCache("001");
    System.out.println(man);

    ///////////////////////////////////
    System.out.println("

使用Cache");
    cachDemo.InitDefault();

    System.out.println("使用Cache get方法  第一次加載");
    try {
        man = cachDemo.getCacheKeyCache("001");
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    System.out.println(man);

    System.out.println("
使用Cache getIfPresent方法  第一次加載");
    man = cachDemo.getIfPresentCache("002");
    System.out.println(man);

    System.out.println("
使用Cache get方法  第一次加載");
    try {
        man = cachDemo.getCacheKeyCache("002");
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    System.out.println(man);

    System.out.println("
使用Cache get方法  已加載過");
    try {
        man = cachDemo.getCacheKeyCache("002");
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    System.out.println(man);

    System.out.println("
使用Cache get方法  已加載過,但是已經(jīng)被剔除掉,驗證重新加載");
    try {
        man = cachDemo.getCacheKeyCache("001");
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    System.out.println(man);

    System.out.println("
使用Cache getIfPresent方法  已加載過");
    man = cachDemo.getIfPresentCache("001");
    System.out.println(man);

    System.out.println("
使用Cache put方法  再次get");
    Man newMan1 = new Man();
    newMan1.setId("001");
    newMan1.setName("額外添加");
    cachDemo.putloadingCache("001",newMan1);
    man = cachDemo.getCacheKeyloadingCache("001");
    System.out.println(man);
}

測試結(jié)果如下:

由上述結(jié)果可以表明,GuavaCache可以在數(shù)據(jù)存儲到達(dá)指定大小后刪除數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)。我們可以設(shè)置定期刪除而達(dá)到定期從數(shù)據(jù)庫、磁盤等其他地方更新數(shù)據(jù)等(再次訪問時數(shù)據(jù)不存在重新獲取)。也可以采用定時刷新的方式更新數(shù)據(jù)

還可以設(shè)置移除監(jiān)聽器對被刪除的數(shù)據(jù)進(jìn)行一些操作。通過RemovalListeners.asynchronous(RemovalListener,Executor)方法將監(jiān)聽器設(shè)為異步,筆者通過實驗發(fā)現(xiàn),異步監(jiān)聽不會在刪除數(shù)據(jù)時立刻調(diào)用監(jiān)聽器方法。

五、GuavaCache結(jié)構(gòu)初探

類結(jié)構(gòu)圖

GuavaCache并不希望我們設(shè)置復(fù)雜的參數(shù),而讓我們采用建造者模式創(chuàng)建Cache。GuavaCache分為兩種Cache:CacheLoadingCache。LoadingCache繼承了Cache,他比Cache主要多了get和refresh方法。多這兩個方法能干什么呢?

在第四節(jié)高級特性demo中,我們看到builder生成不帶CacheLoader的Cache實例。在類結(jié)構(gòu)圖中其實是生成了LocalManualCache類實例。而帶CacheLoader的Cache實例生成的是LocalLoadingCache。他可以定時刷新數(shù)據(jù),因為獲取數(shù)據(jù)的方法已經(jīng)作為構(gòu)造參數(shù)方法存入了Cache實例中。同樣,在get時,不需要像LocalManualCache還需要傳入一個Callable實例。

實際上,這兩個Cache實現(xiàn)類都繼承自LocalCache,大部分實現(xiàn)都是父類做的。

六、總結(jié)回顧

緩存加載:CacheLoader、Callable、顯示插入(put)

緩存回收:LRU,定時(expireAfterAccessexpireAfterWrite),軟弱引用,顯示刪除(Cache接口方法invalidateinvalidateAll)

監(jiān)聽器:CacheBuilder.removalListener(RemovalListener)

清理緩存時間:只有在獲取數(shù)據(jù)時才或清理緩存LRU,使用者可以單起線程采用Cache.cleanUp()方法主動清理。

刷新:主動刷新方法LoadingCache.referesh(K)

信息統(tǒng)計:CacheBuilder.recordStats() 開啟Guava Cache的統(tǒng)計功能。Cache.stats() 返回CacheStats對象。(其中包括命中率等相關(guān)信息)

獲取當(dāng)前緩存所有數(shù)據(jù):cache.asMap(),cache.asMap().get(Object)會刷新數(shù)據(jù)的訪問時間(影響的是:創(chuàng)建時設(shè)置的在多久沒訪問后刪除數(shù)據(jù))

LocalManualCache和LocalLoadingCache的選擇

ManualCache可以在get時動態(tài)設(shè)置獲取數(shù)據(jù)的方法,而LoadingCache可以定時刷新數(shù)據(jù)。如何取舍?我認(rèn)為在緩存數(shù)據(jù)有很多種類的時候采用第一種cache。而數(shù)據(jù)單一,數(shù)據(jù)庫數(shù)據(jù)會定時刷新時采用第二種cache。

具體工程中的情況也歡迎大家與我交流,互相學(xué)習(xí)。

參考資料:

http://www.cnblogs.com/peida/...

https://github.com/tiantianga...

http://www.blogjava.net/DLevi...

http://ifeve.com/google-guava...

更多文章:http://blog.gavinzh.com

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/61831.html

相關(guān)文章

  • Guava學(xué)習(xí)Cache緩存

    摘要:并且添加了監(jiān)聽器,當(dāng)數(shù)據(jù)被刪除后會打印日志。六總結(jié)回顧緩存加載顯示插入緩存回收,定時,,軟弱引用,顯示刪除接口方法,監(jiān)聽器清理緩存時間只有在獲取數(shù)據(jù)時才或清理緩存,使用者可以單起線程采用方法主動清理。 摘要: 學(xué)習(xí)Google內(nèi)部使用的工具包Guava,在Java項目中輕松地增加緩存,提高程序獲取數(shù)據(jù)的效率。一、什么是緩存?根據(jù)科普中國的定義,緩存就是數(shù)據(jù)交換的緩沖區(qū)(稱作Cache)...

    PumpkinDylan 評論0 收藏0
  • Guava 源碼分析(Cache 原理【二階段】)

    摘要:前言在上文源碼分析原理中分析了的相關(guān)原理。我在北京模擬執(zhí)行你在哪兒回復(fù)最后執(zhí)行結(jié)果開始提問提問完畢,我去干其他事了收到消息你在哪兒等待響應(yīng)中。。。。。回復(fù)我在北京這樣一個模擬的異步事件回調(diào)就完成了。 showImg(https://segmentfault.com/img/remote/1460000015643387?w=2048&h=1150); 前言 在上文「Guava 源碼分析...

    msup 評論0 收藏0
  • Guava 源碼分析(Cache 原理【二階段】)

    摘要:前言在上文源碼分析原理中分析了的相關(guān)原理。我在北京模擬執(zhí)行你在哪兒回復(fù)最后執(zhí)行結(jié)果開始提問提問完畢,我去干其他事了收到消息你在哪兒等待響應(yīng)中。。。。。回復(fù)我在北京這樣一個模擬的異步事件回調(diào)就完成了。 showImg(https://segmentfault.com/img/remote/1460000015643387?w=2048&h=1150); 前言 在上文「Guava 源碼分析...

    dack 評論0 收藏0
  • 集中式內(nèi)存緩存 Guava Cache

    摘要:緩存總體可分為兩種集中式緩存和分布式緩存集中式緩存與分布式緩存的區(qū)別其實就在于集中與非集中的概念,其對象可能是服務(wù)器內(nèi)存條硬盤等。內(nèi)存條版本緩存集中在一臺服務(wù)器的一條內(nèi)存條上,為集中式緩存。 背景 緩存的主要作用是暫時在內(nèi)存中保存業(yè)務(wù)系統(tǒng)的數(shù)據(jù)處理結(jié)果,并且等待下次訪問使用。在日長開發(fā)有很多場合,有一些數(shù)據(jù)量不是很大,不會經(jīng)常改動,并且訪問非常頻繁。但是由于受限于硬盤IO的性能或者遠(yuǎn)程...

    Dean 評論0 收藏0
  • 集中式內(nèi)存緩存 Guava Cache

    摘要:緩存總體可分為兩種集中式緩存和分布式緩存集中式緩存與分布式緩存的區(qū)別其實就在于集中與非集中的概念,其對象可能是服務(wù)器內(nèi)存條硬盤等。內(nèi)存條版本緩存集中在一臺服務(wù)器的一條內(nèi)存條上,為集中式緩存。 背景 緩存的主要作用是暫時在內(nèi)存中保存業(yè)務(wù)系統(tǒng)的數(shù)據(jù)處理結(jié)果,并且等待下次訪問使用。在日長開發(fā)有很多場合,有一些數(shù)據(jù)量不是很大,不會經(jīng)常改動,并且訪問非常頻繁。但是由于受限于硬盤IO的性能或者遠(yuǎn)程...

    KitorinZero 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<