Guava Cache-02 源碼閱讀之過期鍵的清理

<code>// 首先從map中取,看看緩存能否命中,是否過期
ReferenceEntry getLiveEntry(Object key, int hash, long now) {
    // 從segment的原子數組中獲取kv鍵值對
    ReferenceEntry e = getEntry(key, hash);
    if (e == null) {
        return null;
    } else if (map.isExpired(e, now)) {
        // 此時僅僅是使用ReentrantLock.tryLock嘗試獲取鎖(CAS方式輕量級獲取鎖)
        tryExpireEntries(now);
        return null;
    }
    return e;
}

// ReentrantLock.tryLock 非公平鎖實現
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // CAS方式輕量級獲取鎖,性能開銷小
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}


// 如果緩存沒有命中
V lockedGetOrLoad(K key, int hash, CacheLoader super K, V> loader)
    throws ExecutionException {
    ReferenceEntry e;
    ValueReference valueReference = null;
    LoadingValueReference loadingValueReference = null;
    boolean createNewEntry = true;

    lock();
    try {     
        long now = map.ticker.read();
        // 佔有鎖後,進行一次集中的清理
        preWriteCleanup(now); 
        ......
    }
}

// 集中的清理
void runLockedCleanup(long now) {
    if (tryLock()) {
        try {
            // 此處清理軟引用與弱引用的鍵值對
            drainReferenceQueues();
            expireEntries(now); // calls drainRecencyQueue
            readCount.set(0);
        } finally {
            unlock();
        }
    }
}


void expireEntries(long now) {
    // recencyQueue來更新accessQueue元素,保證accessQueue的先進先出邏輯
    drainRecencyQueue();
    ReferenceEntry e;
    while ((e = writeQueue.peek()) != null && map.isExpired(e, now)) {
        if (!removeEntry (e, e.getHash(), RemovalCause.EXPIRED)) {
            throw new AssertionError();
        }
    }
    while ((e = accessQueue.peek()) != null && map.isExpired(e, now)) {
        if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) {
            throw new AssertionError();
        }
    }
}

// 從AtomicReferenceArray,writeQueue、accessQueue這3個數據結構中移除該ntry
boolean removeEntry(ReferenceEntry entry, int hash, RemovalCause cause) {
    int newCount = this.count - 1;
    AtomicReferenceArray> table = this.table;
    int index = hash & (table.length() - 1);
    ReferenceEntry first = table.get(index);

    for (ReferenceEntry e = first; e != null; e = e.getNext()) {
        if (e == entry) {
            ++modCount;
            ReferenceEntry newFirst = removeValueFromChain(
                first, e, e.getKey(), hash, e.getValueReference(), cause);
            newCount = this.count - 1;
            // 調整hash數組
            table.set(index, newFirst);
            this.count = newCount; // write-volatile
            return true;
        }
    }

    return false;
}/<code>


分享到:


相關文章: