(翻譯)Google Guava Cache

翻譯自Google Guava Cachehtml

This Post is a continuation of my series on Google Guava, this time covering Guava Cache. Guava Cache offers more flexibility and power than either a HashMap or ConcurrentHashMap, but is not as heavy as using EHCache or Memcached (or robust for that matter, as Guava Cache operates solely in memory). The Cache interface has methods you would expect to see like ‘get’, and ‘invalidate’. A method you won’t find is ‘put’, because Guava Cache is ‘self-populating’, values that aren’t present when requested are fetched or calculated, then stored. This means a ‘get’ call will never return null. In all fairness, the previous statement is not %100 accurate. There is another method ‘asMap’ that exposes the entries in the cache as a thread safe map. Using ‘asMap’ will result in not having any of the self loading operations performed, so calls to ‘get’ will return null if the value is not present (What fun is that?). Although this is a post about Guava Cache, I am going to spend the bulk of the time talking about CacheLoader and CacheBuilder. CacheLoader specifies how to load values, and CacheBuilder is used to set the desired features and actually build the cache.java

 

這篇文章是個人Google Guava系列文章的延續,此次的主題是Guava Cache。Guava Cahce比HashMap和ConcurrentHashMap更靈活也更強大,可是又不像使用EHCache或者Memcached(所以也不像它們這麼健壯,由於Guava Cache只在內存中操做)那麼重量級。Guava Cache有你期待的接口,像是'get',以及'invalide'。一個你不會發現的方法是'put', 由於Guava Cache是「自填充」的,在請求時沒有出現的值會被抓取或者計算,而後儲存起來。因此'get'方法永遠不會返回null。公平地說,上邊一 句並非100%準確的。還有一個方法叫作‘asMap',把cache中的條目做爲一個線程安全的map暴露出來。使用'asMap'並不會執行任何自填充操做,所以,若是值不存在的話,調用'get'會返回null(這麼作有啥意義呢?)儘管這篇blog是關於Guava Cache的,我也會花不少時間講CacheLoader和CacheBuilder。CacheLoader用來指明怎麼樣加載值,而CacheBuilder用於設置你想要的特性,而且實際用來建立cache。git

CacheLoader

CacheLoader is an abstract class that specifies how to calculate or load values, if not present. There are two ways to create an instance of a CacheLoader:github

  1. Extend the CacheLoader<K,V> class算法

  2. Use the static factory method CacheLoader.from緩存

CacheLoader是一個抽象類,用來指明怎麼樣計算或者加載值,若是沒有發現的話(譯註:若是沒有在緩存裏)。有兩種方法來創建一個CacheLoader的實例:安全

  1. 擴展CacheLoader<K,V>類
  2. 使用靜態工程方法CacheLoader.from

If you extend CacheLoader you need to override the V load(K key) method, instructing how to generate the value for a given key. Using the static CacheLoader.from method you build a CacheLoader either by supplying a Function or Supplier interface. When supplying a Function object, the Function is applied to the key to calculate or retrieve the results. Using a Supplier interface the value is obtained independent of the key.併發

若是你擴展CacheLoader,你須要覆蓋V load(K key)方法,來講明怎麼樣從一個指定的key生成value。使用靜態的CacheLoader.from方法來構造CacheLoader時,你或者提供一個Function接口或者Supplier接口(譯註:應該是說「實現了Function或者Supplier接口的對象")。當提供一個Function對象時,這個Function被用於根據key來計算或者獲取結果。使用一個Supplier接口時,value的獲取和key沒有關係。app

CacheBuilder

The CacheBuilder is used to construct cache instances. It uses the fluent style of building and gives you the option of setting the following properties on the cache:less

  • Cache Size limit (removals use a LRU algorithm)

  • Wrapping keys in WeakReferences (Strong references used by default for keys)

  • Wrapping values in either WeakReferences or SoftReferences (Strong references used by default)

  • Time to expire entires after last access

  • Time based expiration of entries after being written or updated

  • Setting a RemovalListener that can recieve events once an entry is removed from the cache

  • Concurrency Level of the cache (defaults to 4)

CacheBuilder被用來建立cache實例(譯註:是指被cache的實例)。它使用fluent style(譯註:就是.xx().xx().xx()的模式)來建立,使你能夠指定cache的下列的屬性: 

  • Cache大小限制('移除'是使用LRU算法)
  • 是否把keys包裝成WeakReference(默認對於key是使用strong reference(譯註:Java的弱引用和強引用))
  • 把值包裝成WeakReference或者SoftReference(默認使用strong reference)
  • 在最後訪問一個條目(譯註:entry,就是cache裏的kv對)後多長時間過這個條目過時(expire)
  • 在寫入或者更新之後多長時間這個條目過時
  • 設置一個RemovalListener,在一個條目過時之後,這個RemovalListener用來接收事件(譯註:指'哪一個條目'過時了,這個事件)
  • cache的併發度(默認爲4)

The concurrency level option is used to partition the table internally such that updates can occur without contention. The ideal setting would be the maximum number of threads that could potentially access the cache at one time. Here is an example of a possible usage scenario for Guava Cache.

併發度選擇用來在給內部的表作分區(譯註:指cache實現時,在內部存儲條目用的表),使得更新能夠無競爭的進行。最理想的設置是有可能同時訪問這個cache的線程的數目。下面是一個可能使用Guava Cache的場景

public class PersonSearchServiceImpl implements SearchService<List<Person>> {

public PersonSearchServiceImpl(SampleLuceneSearcher luceneSearcher, SampleDBService dbService) {
        this.luceneSearcher = luceneSearcher;
        this.dbService = dbService;
        buildCache();
    }

    @Override
    public List<Person> search(String query) throws Exception {
        return cache.get(query);
    }

    private void buildCache() {
        cache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(1000)
                .build(new CacheLoader<String, List<Person>>() {
                    @Override
                    public List<Person> load(String queryKey) throws Exception {
                        List<String> ids = luceneSearcher.search(queryKey);
                        return dbService.getPersonsById(ids);
                    }
                });
    }
}

In this example, I am setting the cache entries to expire after 10 minutes of being written or updated in the cache, with a maximum amount of 1,000 entires. Note the usage of CacheLoader on line 15.

在這個例子中,我設置cache的條目會在寫入或者更新10分鐘後過時,最大數目數量是1000。注意第15行的CacheLoader的例子

RemovalListener

The RemovalListener will receive notification of an item being removed from the cache. These notifications could be from manual invalidations or from a automatic one due to time expiration or garbage collection. The RemovalListener<K,V> parameters can be set to listen for specific type. To receive notifications for any key or value set them to use Object. It should be noted here that a RemovalListener will receive a RemovalNotification<K,V> object that implements the Map.Entry interface. The key or value could be null if either has already been garbage collected. Also the key and value object will be strong references, regardless of the type of references used by the cache.

RemovalListener會在條目被從cache移除之後收到通知。這個通知可能源於手動地使條目失效,或者因爲時間過時或者垃圾回收而自動地移除條目。RemovalListener<K,V>的類型參數能夠被設置以監聽指定的類型。若是要接收任何的kv的通知,把它們設成Object。須要說明的是,RemovalListener會收到一個RemovalNotification<K,V>類型的對象,這個對象實現了Map.Entry接口。若是key或者value被垃圾回收了,那麼key和value可能會爲null.並且key和value對象是是strong reference,無論在cache中的時候的reference的類型。

CacheStats

There is also a very useful class CacheStats that can be retrieved via a call to Cache.stats(). The CacheStats object can give insight into the effectiveness and performance of your cache by providing statistics such as:

有一個很是有用CacheStats類的對象,可使用Cache.status()來獲取。CacheStats對象經過給你下面的統計,能夠給出關於你的cache的效率和性能的洞察。

  • hit count  命中總數

  • miss count 未命中總數

  • total load time 總的加載時間

  • total requests 總的請求數目

CacheStats provides many other counts in addition to the ones listed above.

除了上邊列出的統計結果,CacheStatus還提供了不少其它的值。

Conclusion

The Guava Cache presents some very compelling functionality. The decision to use a Guava Cache really comes down to the tradeoff between memory availability/usage versus increases in performance. I have added a unit test CacheTest demonstrating the usages discussed here. As alway comments and suggestions are welcomed. Thanks for your time.

GuavaCache提供了一些很是有競爭力的功能。使用Guava Cache源於對可用/使用的內存以及性能的折衷。我添加了一個單元測試來展現這裏討論的使用狀況。像往常同樣,歡迎評論和建議。謝謝你的時間。

相關文章
相關標籤/搜索