guava cache 代碼分析1 -- 5

  • 建立緩存實體LoadingCache

    LoadingCache只是個接口,具體的還是LocalLoadingCache,其實真正管理緩存的是LocalCache。

class LocalLoadingCache<K, V> extends LocalManualCache<K, V> implements   LoadingCache<K, V> {
    LocalLoadingCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader){
      super(new LocalCache<K, V>(builder, checkNotNull(loader)));
    }

    其餘的都交給了LocalCache
}

先來看下各個字段所代表的含義

CacheBuilder.newBuilder()
.concurrencyLevel(8) //根據這個來計算分成幾個緩存區
.expireAfterWrite(8, TimeUnit.SECONDS)//設置寫緩存後8秒鐘過期
.initialCapacity(10)//設置緩存容器的初始容量爲10
.maximumSize(100) //設置緩存最大容量爲100,超過100之後就會按照LRU最近雖少使用算法來移除緩存項
...

以下的maxWeight 就是指maximumSize

1. 先看LocalCache的Segment[] 數組; 緩存區

分成幾段緩存區segment,獲取的時候根據key的hashcode值計算來定位到segment .這主要是爲了查詢效率

在LocalCache的構造器中創建好了segment數組.
1 ) 創建segment數組. 先根據concurrencyLevel 來計算出數組的大小,默認是4.

    int segmentShift = 0;
    int segmentCount = 1;
    //個數< concurrencyLevel & (沒有設置回收超出數 || 個數*20 <=  回收超出數)
    while (segmentCount < concurrencyLevel && (maxWeight <0 || segmentCount * 20 <= maxWeight)) {
      ++segmentShift;
      segmentCount <<= 1; //相當於segmentCount = segmentCount*2
    }
    //創建好總共分爲幾個hash段
    this.segments = new Segment[segmentCount];

2 ) 根據初始化容量initialCapacity,爲每個緩存區分配初始化緩存數

根據initialCapacity(默認是16,這個是緩存初始化個數)和緩存區的個數(segment數組的個數)來計算出平均每個segment裏的緩存數

    int segmentSize = 1;
    int segmentCapacity = initialCapacity / segmentCount;
    if (segmentCapacity * segmentCount < initialCapacity) {
      ++segmentCapacity;
    }
    while (segmentSize < segmentCapacity) {
      segmentSize <<= 1;
    }

3 ) 計算每個緩存區中最大的緩存數]
根據緩存的最大容量和緩存區數,爲每個緩存區分配合理的緩存個數

 private List<Integer> getSegmentNum() {
    List<Integer> arr = new ArrayList<Integer>();
    long maxSegmentWeight = maxWeight / segmentCount + 1;
    long remainder = maxWeight % segmentCount;
    for (int i = 0; i < this.segments.length; ++i) {
      //限制緩存數時,爲每個hash段內的限制數分配下
       if(maxWeight >=0 ) {
          if (i == remainder) {
             maxSegmentWeight--;
          arr.add(maxSegmentWeight);
        }else
          arr.add(-1);
     }
    return arr ;
  }

4 ) 初始化緩存區Segment

   List<Integer> arr = getSegmentNum();
   int index = 0;
   for(Integer i : arr ) {
       this.segments[index++] = new Segment<K, V>     (segmentSize,i,builder.getStatsCounterSupplier().get());
    }

5) 根據key定位緩存區

 V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException {
    int hash = hash(checkNotNull(key)); //根據key的hashcode計算得出來的值
    return segments[(hash >>> segmentShift) & segmentMask].get(key, hash, loader); 找到他在緩存區
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章