内存缓存GuavaCache源码解析

1、前言

Guava Cache是一个全内存的本地缓存,它提供了线程安全的实现机制。其简单易用、性能好是本地缓存的不二之选。Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache不回收元素,但考虑到其会自动加载缓存,在某些场景也是很有用的。

Guava Cache适用于消耗内存空间来提升速度、某些键会被查询一次以上、缓存中存放的数据总量不会超出内存容量的应用场景。Guava Cache是单个应用运行时的本地缓存,它不把数据存放到文件或外部服务器,如果要得到持久缓存可以尝试使用Redis或者Memcached。

缓存是指暂时在内存中保存某些数据的处理结果,等待下次访问可以快速取出使用。在日常开发中,受限于IO性能或自身业务系统的数据处理能力,获取数据可能非常费时。系统某些数据请求量很大、频繁IO、重复逻辑处理,都会导致系统出现瓶颈。缓存则可以较好解决这样的问题。缓存的作用是将这些数据保存在内存中,当有其它线程或客户端需相同数据时,则可直接从缓存内存块中取出数据。这样,不但可以提高系统的响应时间,也可以节省处理数据的资源消耗,整体上来系统性能会有大大的提升。


2、源码分析

本文以Guava-18.0.jar中源码为例进行阐述。

通常情况下,Guava cache在程序中会以com.google.common.cache.Cache或com.google.common.cache.LoadingCache的形式出现。Cache是接口,LoadingCache也是接口,不过其继承了Cache。

public interface Cache<K, V> {
   }

public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
   }

它们共有的方法都存在Cache中,如下所示:


  /**
   * Returns the value associated with {
   @code key} in this cache, or {
   @code null} if there is no
   */
  @Nullable
  V getIfPresent(Object key);

  /**
   * Returns the value associated with {
   @code key} in this cache, obtaining that value from
   */
  V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;

  /**
   * Returns a map of the values associated with {
   @code keys} in this cache. 
   */
  ImmutableMap<K, V> getAllPresent(Iterable<?> keys);

  /**
   * Associates {
   @code value} with {
   @code key} in this cache. If the cache previously contained a value associated with {
   @code key}, the old value is replaced 
 */
  void put(K key, V value);

  /**
   * Copies all of the mappings from the specified map to the cache
   */
  void putAll(Map<? extends K,? extends V> m);

  /**
   * Discards any cached value for key {
   @code key}.
   */
  void invalidate(Object key);

  /**
   * Discards any cached values for keys {
   @code keys}.
   */
  void invalidateAll(Iterable<?> keys);

  /**
   * Discards all entries in the cache.
   */
  void invalidateAll();

  /**
   * Returns the approximate number of entries in this cache.
   */
  long size();

  /**
   * Returns a current snapshot of this cache's cumulative statistics.
   */
  CacheStats stats();

  /**
   * Returns a view of the entries stored in this cache as a thread-safe map.
   */
  ConcurrentMap<K, V> asMap();

  /**
   * Performs any pending maintenance operations needed by the cache.
   */
  void cleanUp();

比较常用的方法有:

  V getIfPresent(Object key);

  V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;

  void put(K key, V value);

  void putAll(Map<? extends K,? extends V> m);

Cacahe是接口我们无法使用,Guava中提供了创建者CacheBuilder可以创建一个Cache,实现如下:

Cache<String, Person> caches = CacheBuilder.newBuilder().
                // 设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                        maximumSize(100).
                        // 设置写缓存后8秒钟过期
                        expireAfterWrite(8, TimeUnit.SECONDS).
                        // 设置缓存容器的初始容量为10
                        initialCapacity(10).
                        // 当缓存中个数大于设置个数时就会移除
                        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();

//其中最后带有参数的build实现
//在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(new CacheLoader<Integer, Student>() {
                            @Override
                            public Student load(Integer key) throws Exception {
                                System.out.println("loading student " + key);
                                Student student = new Student();
                                student.setId(key);
                                student.setName("name " + key);
                                return student;
                            }
                        });

CacheBuilder使用了创建者模式,对于内部的成员变量赋值,它都提供了对应的构建方法,代码如下所示:

 /**
     //直接new了一个CacheBuilder
   * Constructs a new {@code CacheBuilder} instance with default settings, including strong keys,
   * strong values, and no automatic eviction of any kind.
   */
  public static CacheBuilder<Object, Object> newBuilder() {
    return new CacheBuilder<Object, Object>();
  }


//例如设置Cache缓存最大容量

  public CacheBuilder<K, V> maximumSize(long size) {
    checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
        this.maximumSize);
    checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
        this.maximumWeight);
    checkState(this.weigher == 
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值