Guava Cache本地緩存

Guava介紹

Guava是一種基於開源的Java庫,其中包含谷歌正在由他們不少項目使用的不少核心庫。java

這個庫是爲了方便編碼,並減小編碼錯誤。git

這個庫提供用於集合,緩存,支持原語,併發性,常見註解,字符串處理,I/O和驗證的實用方法。github

Guava Cache適用場景

1 消耗一些內存空間來提高速度;編程

2 緩存中存放的數據總量不會超出內存容量。緩存

(Guava Cache是單個應用運行時的本地緩存,不把數據存放到文件或外部服務器(Memcached, Redis))服務器

Guava Cache介紹

數據結構:ConcurrentHash (The returned cache is implemented as a hash table with similar performance characteristics to ConcurrentHashMap.)數據結構

主要特性(詳見下面的相關連接):併發

    1 自動加載app

    2 回收策略:yii

        2.1 基於容量

        2.2 基於存活時間

        2.3 基於權重

        2.4 基於引用

    3 移除監聽器

    4 緩存訪問統計

主要接口:CacheBuilder, LoadingCache, CacheStats

使用示例:

public class CacheProTest {
    LoadingCache<Long, Person> cache;
    private int cacheTimeoutSeconds = 10; // 10秒

    Integer counter = 1;

    @Before
    public void initialize() {
        System.out.println("初始化");

        cache = CacheBuilder.newBuilder()
                        /* 回收策略:基於容量(least-recently-used eviction when a maximum size is exceeded) */
                        .maximumSize(10) 
                        // .initialCapacity(initialCapacity)
                        
                        /* 回收策略:基於存活時間(time-based expiration of entries, measured since last access or last write) */
                        .expireAfterWrite(cacheTimeoutSeconds, TimeUnit.SECONDS)
                        // .expireAfterAccess(duration, unit)
                        // .refreshAfterWrite(duration, unit)
                        
                        /* 回收策略:基於權重 */
                        // .maximumWeight(maximumWeight)
                        // .weigher(weigher)

                        /* 回收策略:基於引用(keys automatically wrapped in weak references, values automatically wrapped in weak or soft references)*/
                        // .weakKeys()
                        // .weakValues()
                        // .softValues()
                        
                        // 設置併發數爲5,即同一時間最多隻能有5個線程往cache執行寫入操做
                        // .concurrencyLevel(concurrencyLevel)

                        /* 緩存訪問統計(accumulation of cache access statistics) */
                        .recordStats()
                        
                        /* 移除監聽器(notification of evicted (or otherwise removed) entries) */
                        // .removalListener(listener)

                        .build(new CacheLoader<Long, Person>() {

                            /* 自動加載(automatic loading of entries into the cache) */
                            @Override
                            public Person load(Long id) throws Exception {
                                System.out.println("獲取值, id=" + id);

                                // 調用接口獲取值
                                Person p = new Person();
                                p.setId(id);
                                p.setName("name" + counter.toString());
                                counter++;

                                return p;
                            }
                        });
    }

    @Test
    public void test1() {
        try {
            /* 獲值 */
            // ConcurrentMap<Long, Person> asMap = cache.asMap();

            // cache.get(key); //
            // cache.getAll(keys);

            // cache.getIfPresent(key);
            // cache.getAllPresent(keys);

            // cache.size();

            /* 存值 */
            // cache.put(key, value);
            // cache.putAll(m); // Map<? extends K, ? extends V> m

            /* 移除/刪除 */
            // cache.refresh(key);
            // cache.invalidate(key);
            // cache.invalidateAll();
            // cache.invalidateAll(keys);
            // cache.cleanUp();

            /* 緩存訪問統計 */
            CacheStats stats = cache.stats();
            stats.averageLoadPenalty();
            stats.evictionCount();
            stats.hitCount();
            stats.hitRate();
            stats.loadCount();
            stats.loadExceptionCount();
            stats.loadExceptionRate();
            stats.loadSuccessCount();
            stats.missCount();
            stats.missRate();
            stats.requestCount();
            stats.totalLoadTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Test
    public void test2() {
        try {
            Long id = 1L;
            Person person1 = cache.get(id);

            Thread.sleep(3L * 1000L);
            Person person2 = cache.get(id);

            Thread.sleep(11L * 1000L);
            Person person3 = cache.get(id);

            System.out.println(person1);
            System.out.println(person2);
            System.out.println(person3);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Person implements Serializable {
    private static final long serialVersionUID = 1L;

    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

  

Guava Cache使用時須要關注的點

1 瞭解LoadingCache.refresh

正如LoadingCache.refresh(K)所聲明,刷新表示爲鍵加載新值,這個過程能夠是異步的。

在刷新操做進行時,緩存仍然能夠向其餘線程返回舊值,而不像回收操做,讀緩存的線程必須等待新值加載完成。

若是刷新過程拋出異常,緩存將保留舊值,而異常會在記錄到日誌後被丟棄[swallowed]。

重載CacheLoader.reload(K, V)能夠擴展刷新時的行爲,這個方法容許開發者在計算新值時使用舊的值。

 

2 瞭解 清理時機

使用CacheBuilder構建的緩存不會"自動"執行清理和回收工做,也不會在某個緩存項過時後立刻清理,也沒有諸如此類的清理機制。

它會在寫操做時順帶作少許的維護工做,或者偶爾在讀操做時作——若是寫操做實在太少的話。

所以使用LoadingCache.size() 必定要關注這個點。

 

相關連接

github 地址

易寶教程:Guava教程

CSDN:GuavaCache簡介

併發編程網:[Google Guava] 3-緩存

相關文章
相關標籤/搜索