Guava LoadingCache用法

1.Guava中的cache

cache在任何系統中都是一種被廣泛使用的數據中間件。對於小規模的緩存數據,Guava中的cache會很實用,使用得也很多。下面我們就針對Guava中的cache做個簡單分析。

/**
 * A semi-persistent mapping from keys to values. Cache entries are manually added using
 * {@link #get(Object, Callable)} or {@link #put(Object, Object)}, and are stored in the cache until
 * either evicted or manually invalidated.
 *
 * <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed
 * by multiple concurrent threads.
 *
 * @author Charles Fry
 * @since 10.0
 */
@GwtCompatible
public interface Cache<K, V> 

從jdk源碼中的註釋裏,我們可以得到如下信息:
1.Cache接口是一種半持久化的KV結構。
2.Cache可以使用get(Object, Callable)方法或者put方法手動添加元素對。
3.這些KV會一直有效,直到被驅逐或者手動設置爲無效。
4.該接口事線程安全的,可以被多個線程併發訪問。

2.LoadingCache

Guava Cache與ConcurrentMap比較相似,最大的不同在於ConcurrentMap會一直保存添加的元素直到被手動移除。而Guava Cache爲了限制內存的使用會自動回收元素,而且在很多場景下,需要自動加載緩存,這也是對比ConcurrentMap的優勢。

LoadingCache繼承了Cache接口。LoadingCache讀取一個指定key的數據時,如果key不存在,LoadingCache會執行加載數據到緩存。

3.LoadingCache例子

import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.List;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyCacheLoader extends CacheLoader<String, List<Integer>>  {

    private final ListeningExecutorService executorService =
            MoreExecutors.listeningDecorator(new ThreadPoolExecutor(16,
                    100,
                    60,
                    TimeUnit.SECONDS,
                    new SynchronousQueue<>(),
                    new NamedThreadFactory("xxx")));

    protected ListeningExecutorService executorService() {
        return executorService;
    }

    @Override
    public List<Integer> load(String key) {
        long startTime = System.currentTimeMillis();
        List<Integer> result = (一般爲數據庫操作,獲取數據)
        return result;
    }

    @Override
    public ListenableFuture<List<Integer>> reload(String key, List<Integer> oldValue) {
        return executorService().submit(() -> load(key));
    }

}


public class MyLoadingCache {

    private static final int CACHE_TTL = 60 * 6;
    private static final int CACHE_MAX_SIZE = 10000;

    private static LoadingCache<String, List<Integer>> myLoadingCache = CacheBuilder.newBuilder()
            .refreshAfterWrite(CACHE_TTL, TimeUnit.MINUTES)
            .maximumSize(CACHE_MAX_SIZE)
            .build(new ReaderOnlineBadContentCacheLoader());
  }

LoadingCache類型的對象是通過CacheBuilder進行構建的,從構建過程中很明顯可以看出來是使用的build模式,調用的每個方法返回的都是CacheBuilder本身,直到build方法被調用,才返回LoadingCache對象。

build方法需要傳入一個CacheLoader對象,CacheLoader是一個抽象類,需要重寫load方法。

@GwtCompatible(emulated = true)
public abstract class CacheLoader<K, V> {
...
  public abstract V load(K key) throws Exception;
}

如果我們調用LoadingCache中的get方法,緩存不存在相對應的key的數據,那麼CacheLoader會自動調用load方法去從外部加載數據進來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章