guava 緩存過時策略

google的guava可謂鼎鼎有名,最近在研究緩存,也就看看它是怎麼處理緩存過時問題的;首先它並無經過在後臺起一個線程,不停去輪詢。不這麼作主要是爲了效率吧,也就是所謂的惰性移除,在get時判斷是否過時。那若是一直不訪問,可能存在內存泄漏問題。java

示例代碼:算法

Cache<Object, Object> cache = CacheBuilder.newBuilder().expireAfterAccess(2,TimeUnit.SECONDS).build();
        cache.put("a",1);
        System.out.println(cache.getIfPresent("a"));

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(cache.getIfPresent("a"));

1,CacheBuilder默認的緩存實現爲LocalCache,因此這裏咱們主要去研究LocalCache的getIfPresent 便可緩存

2,經過觀察,咱們能夠猜出LocalCache 是用相似於ConcurrentHashMap 的數據結構來保存數據的數據結構

3,這裏咱們主要看其Segment 的get 方法,而後進入getLiveEntry 方法,看名字感受跟存活有關,點進去post

ReferenceEntry<K, V> getLiveEntry(Object key, int hash, long now) {
//獲取值
      ReferenceEntry<K, V> e = getEntry(key, hash);
      if (e == null) {//若是爲空,返回空
        return null;
      } else if (map.isExpired(e, now)) {//判斷是否過時
        tryExpireEntries(now);
        return null;
      }
      return e;
    }


boolean isExpired(ReferenceEntry<K, V> entry, long now) {
    checkNotNull(entry);
    if (expiresAfterAccess() && (now - entry.getAccessTime() >= expireAfterAccessNanos)) {
      return true;
    }
    if (expiresAfterWrite() && (now - entry.getWriteTime() >= expireAfterWriteNanos)) {
      return true;
    }
    return false;
  }

maximumSize做用原理,猜測:應該是在put緩存時,檢查是否達到了最大值,若是達到則用LRU算法移除一個cacheui

1,觀察LocalCache#putgoogle

V put(K key, int hash, V value, boolean onlyIfAbsent) {
      lock();
      try {
       ...
        evictEntries(newEntry);//這行代碼,看名字感受就是它,點進去看
        return null;
      } finally {
        unlock();
        postWriteCleanup();
      }
    }

void evictEntries(ReferenceEntry<K, V> newest) {
     ....

      while (totalWeight > maxSegmentWeight) {
        ReferenceEntry<K, V> e = getNextEvictable();
        if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) {
          throw new AssertionError();
        }
      }
    }

這裏咱們不妨看看它的LRU算法是如何實現的線程

ReferenceEntry<K, V> getNextEvictable() {
      for (ReferenceEntry<K, V> e : accessQueue) {
        int weight = e.getValueReference().getWeight();
        if (weight > 0) {
          return e;
        }
      }
      throw new AssertionError();
    }

發現它是用隊列實現的,也就是在插入新緩存是有排序。code

總結:排序

咱們時常會有本地緩存的需求,這時不妨看看google是怎麼作的,能夠給咱們一個參考

相關文章
相關標籤/搜索