guava學習--cache


轉載:http://outofmemory.cn/java/guava/cache/how-to-use-guava-cache

     http://www.cnblogs.com/parryyang/p/5777019.html

     https://yq.aliyun.com/articles/46900            //源碼解析

 

  作為Google的core libraries,直接提供Cache實現,足以證明Cache應用的廣泛程度。 然而作為工具庫中的一部分,我們自然不能期待Guava對Cache有比較完善的實現。因而Guava中的Cache只能用於一些把Cache作為一種輔助設計的項目或者在項目的前期為了實現簡單而引入。

Guava Cache有兩種創建方式:

  1. cacheLoader
  2. callable callback

  通過這兩種方法創建的cache,和通常用map來緩存的做法比,不同在於,這兩種方法都實現了一種邏輯——從緩存中取key X的值,如果該值已經緩存過了,則返回緩存中的值,如果沒有緩存過,可以通過某個方法來獲取這個值。但不同的在於cacheloader的定義比較寬泛,是針對整個cache定義的,可以認為是統一的根據key值load value的方法。而callable的方式較為靈活,允許你在get的時候指定。

cacheLoader方式實現實例:

public static void main(String[] args) throws ExecutionException, InterruptedException{         //緩存接口這里是LoadingCache,LoadingCache在緩存項不存在時可以自動加載緩存         LoadingCache<Integer,Student> studentCache                 //CacheBuilder的構造函數是私有的,只能通過其靜態方法newBuilder()來獲得CacheBuilder的實例                 = CacheBuilder.newBuilder()                 //設置並發級別為8,並發級別是指可以同時寫緩存的線程數
          //refreshAfterWrite(3, TimeUnit.HOURS)// 給定時間內沒有被讀/寫訪問,則回收。                 .concurrencyLevel(8)                 //設置寫緩存后8秒鍾過期                 .expireAfterWrite(8, TimeUnit.SECONDS)                 //設置緩存容器的初始容量為10                 .initialCapacity(10)                 //設置緩存最大容量為100,超過100之后就會按照LRU最近雖少使用算法來移除緩存項                 .maximumSize(100)                 //設置要統計緩存的命中率                 .recordStats()                 //設置緩存的移除通知                 .removalListener(new RemovalListener<Object, Object>() {                     @Override                     public void onRemoval(RemovalNotification<Object, Object> notification) {                         System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());                     }                 })                 //build方法中可以指定CacheLoader,在緩存不存在時通過CacheLoader的實現自動加載緩存
          ///** 當本地緩存命沒有中時,調用load方法獲取結果並將結果緩存 **/                   .build(                         new CacheLoader<Integer, Student>() {                             @Override                             public Student load(Integer key) throws Exception {                                 System.out.println("load student " + key);                                 Student student = new Student();                                 student.setId(key);                                 student.setName("name " + key);                                 return student;                             }                         }                 );         for (int i=0;i<20;i++) {             //從緩存中得到數據,由於我們沒有設置過緩存,所以需要通過CacheLoader加載緩存數據             Student student = studentCache.get(1);             System.out.println(student);             //休眠1秒             TimeUnit.SECONDS.sleep(1);         }         System.out.println("cache stats:");         //最后打印緩存的命中率等 情況         System.out.println(studentCache.stats().toString());     }
cache stats: CacheStats{hitCount=17, missCount=3, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=1348802, evictionCount=2}

看看到在20此循環中命中次數是17次,未命中3次,這是因為我們設定緩存的過期時間是寫入后的8秒,所以20秒內會失效兩次,另外第一次獲取時緩存中也是沒有值的,所以才會未命中3次,其他則命中。

guava的內存緩存非常強大,可以設置各種選項,而且很輕量,使用方便。另外還提供了下面一些方法,來方便各種需要:

  1. ImmutableMap<K, V> getAllPresent(Iterable<?> keys) 一次獲得多個鍵的緩存值
  2. putputAll方法向緩存中添加一個或者多個緩存項
  3. invalidate 和 invalidateAll方法從緩存中移除緩存項
  4. asMap()方法獲得緩存數據的ConcurrentMap<K, V>快照
  5. cleanUp()清空緩存
  6. refresh(Key) 刷新緩存,即重新取緩存數據,更新緩存

callable callback的實現:

Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();  
        String resultVal = cache.get("jerry", new Callable<String>() {  
            public String call() {  
                String strProValue="hello "+"jerry"+"!";                
                return strProValue;
            }  
        });  
        System.out.println("jerry value : " + resultVal);
        
        resultVal = cache.get("peida", new Callable<String>() {  
            public String call() {  
                String strProValue="hello "+"peida"+"!";                
                return strProValue;
            }  
        });  
        System.out.println("peida value : " + resultVal);

 

guava Cache數據移除:

  guava做cache時候數據的移除方式,在guava中數據的移除分為被動移除和主動移除兩種。
  被動移除數據的方式,guava默認提供了三種方式:
  1.基於大小的移除:看字面意思就知道就是按照緩存的大小來移除,如果即將到達指定的大小,那就會把不常用的鍵值對從cache中移除。
  定義的方式一般為 CacheBuilder.maximumSize(long),還有一種一種可以算權重的方法,個人認為實際使用中不太用到。就這個常用的來看有幾個注意點,
    其一,這個size指的是cache中的條目數,不是內存大小或是其他;
    其二,並不是完全到了指定的size系統才開始移除不常用的數據的,而是接近這個size的時候系統就會開始做移除的動作;
    其三,如果一個鍵值對已經從緩存中被移除了,你再次請求訪問的時候,如果cachebuild是使用cacheloader方式的,那依然還是會從cacheloader中再取一次值,如果這樣還沒有,就會拋出異常
  2.基於時間的移除:guava提供了兩個基於時間移除的方法
    expireAfterAccess(long, TimeUnit)  這個方法是根據某個鍵值對最后一次訪問之后多少時間后移除
    expireAfterWrite(long, TimeUnit)  這個方法是根據某個鍵值對被創建或值被替換后多少時間移除
  3.基於引用的移除:
  這種移除方式主要是基於java的垃圾回收機制,根據鍵或者值的引用關系決定移除
  主動移除數據方式,主動移除有三種方法:
  1.單獨移除用 Cache.invalidate(key)
  2.批量移除用 Cache.invalidateAll(keys)
  3.移除所有用 Cache.invalidateAll()
  如果需要在移除數據的時候有所動作還可以定義Removal Listener,但是有點需要注意的是默認Removal Listener中的行為是和移除動作同步執行的,如果需要改成異步形式,可以考慮使用RemovalListeners.asynchronous(RemovalListener, Executor)   (******)

 


免責聲明!

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



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