1. 程式人生 > >Guava Cache本地緩存

Guava Cache本地緩存

memcach cati rds 字符串 tps eve adc thread I/O

Guava介紹

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

這個庫是為了方便編碼,並減少編碼錯誤。

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

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 自動加載

2 回收策略:

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-緩存

Guava Cache本地緩存