缓存框架Guava Cache部分源码分析

本文分析了Guava Cache的部分源码,探讨了其与OSCache的区别,重点介绍了Guava Cache的数据结构、CacheBuilder、LocalCache、Segment以及get方法的实现。Guava Cache通过Segment数组实现并发安全,利用弱引用和软引用控制内存,并提供了LRU淘汰策略、自动加载等功能,展示了其在本地缓存领域的高效与灵活性。
摘要由CSDN通过智能技术生成

前言

在本地缓存中,最常用的就是OSCache和谷歌的Guava Cache。其中OSCache在07年就停止维护了,但它仍然被广泛的使用。谷歌的Guava Cache也是一个非常优秀的本地缓存,使用起来非常灵活,功能也十分强大,可以说是当前本地缓存中最优秀的缓存框架之一。之前我们分析了OSCache的部分源码,本篇就通过Guava Cache的部分源码,来分析一下Guava Cache的实现原理。

在分析之前,先弄清数据结构的使用。之前的文章提到,OSCache使用了一个扩展的HashTable,作为缓存的数据结构,由于在get操作上,没有使用同步的方式,通过引入一个更新状态数据结构,来控制并发访问的安全。Guava Cache也是使用一个扩展的HashTable作为其缓存数据结构,然而,在实现上,和OSCache是完全不同的。

Guava Cache所用的HashTable和ConcurrentHashMap十分相似,通过引入一个Segment数组,对HashTable进行分段,通过分离锁、final以及volatile的配合,实现了并发环境下的线程安全,同时,性能也非常高(每个Segment段的操作互不影响,即使写操作,只要在不同的Segment上,也完全可以并发的执行)。具体的原理,可以参考ConcurrentHashMap的实现,这里就不进行具体的剖析了。

数据结构核心部分可以通过下面的图形表示:
Guava Cache数据结构图解

CacheBuilder


Guava Cache特性

CacheBuilder集成了创建缓存所需的各种参数。正如官方文档介绍的:CacheBuilder将创建一个LoadingCache和Cache的实例,该实例可以包含下面任何特性

  • 自动将内容加载到缓存中
  • LRU淘汰策略
  • 根据上一次访问时间或写入时间决定缓存过期
  • key关键字可以采用弱引用(WeakReference)
  • value值可以采用弱引用(WeakReference)以及软引用(SoftReference)
  • 缓存移除或回收进行通知
  • 统计缓存访问性能信息

所有特性都是可选的,创建的缓存可以包含上面所有的特性,也可以都不使用,具有很强的灵活性。

构造示例

下面是一个简单的使用例子:

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
       .maximumSize(10000)
       .expireAfterWrite(10, TimeUnit.MINUTES)
       .removalListener(MY_LISTENER)
       .build(
           new CacheLoader<Key, Graph>() {
             public Graph load(Key key) throws AnyException {
               return createExpensiveGraph(key);
             }
           });}

还可以这样写:

String spec = "maximumSize=10000,expireAfterWrite=10m";

   LoadingCache<Key, Graph> graphs = CacheBuilder.from(spec)
       .removalListener(MY_LISTENER)
       .build(
           new CacheLoader<Key, Graph>() {
             public Graph load(Key key) throws AnyException {
               return createExpensiveGraph(key);
             }
           });}

说明:上面的例子指定Cache容量最大为10000,并且写入后经过10分钟自动过期,并指定了一个缓存移除的消息监听器,可以在缓存移除的时候,进行指定的操作。

接下来,根据CacheBuilder的源码进行简要的分析:

CacheBuilder中一些重要的参数
  //默认容量
  private static final int DEFAULT_INITIAL_CAPACITY = 16;
  //默认并发程度(segement大小就是通过这个计算)
  private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
  //默认失效时间
  private static final int DEFAULT_EXPIRATION_NANOS = 0;
  //默认刷新时间
  private static final int DEFAULT_REFRESH_NANOS = 0;
  //默认性能计数器
  static final Supplier<? extends StatsCounter> NULL_STATS_COUNTER = Suppliers.ofInstance(
      new StatsCounter() {
        @Override
        public void recordHits(int count) {}

        @Override
        public void recordMisses(int count) {}

        @Override
        public void recordLoadSuccess(long loadTime) {}

        @Override
        public void recordLoadException(long loadTime) {}

        @Override
        public void recordEviction() {}

        @Override
        public CacheStats snapshot() {
          return EMPTY_STATS;
        }
      });
  static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0);

  static final Supplier<StatsCounter> CACHE_STATS_COUNTER =
      new Supplier<StatsCounter>() {
    @Override
    public StatsCounter get() {
      return new SimpleStatsCounter();
    }
  };
  //移除事件监听器(默认为空)
  enum NullListener implements RemovalListener<Object, Object> {
    INSTANCE;

    @Override
    public void onRemoval(RemovalNotification<Object, Object> notification) {}
  }

  enum OneWeigher implements Weigher<Object, Object> {
    INSTANCE;

    @Override
    public int weigh(Object key, Object value) {
      return 1;
    }
  }

  static final Ticker NULL_TICKER = new Ticker() {
    @Override
    public long read() {
      return 0;
    }
  };

  static final int UNSET_INT = -1;

  boolean strictParsing = true;
  //初始容量
  int initialCapacity = UNSET_INT;
  //并发程度,
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值