⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.java

📁 BBS-CS(天乙社区) v5.2.2源码版
💻 JAVA
字号:
package com.laoer.bbscs.util;

import java.util.*;

/**
 * <p>Title: 天乙社区V5.0</p>
 * <p>Description: BBS-CS天乙社区V5.0</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: laoer.com</p>
 * @author 龚天乙
 * @version 5.0
 */

public class Cache
    implements Cacheable {

  protected static long currentTime = CacheTimer.currentTime;

  protected HashMap cachedObjectsHash;

  protected LinkedList lastAccessedList;

  protected LinkedList ageList;

  protected int maxSize = 128 * 1024;

  protected int size = 0;

  protected long maxLifetime = -1;

  protected long cacheHits, cacheMisses = 0L;

  public Cache() {
    // Our primary data structure is a hash map. The default capacity of 11
    // is too small in almost all cases, so we set it bigger.
    cachedObjectsHash = new HashMap(103);

    lastAccessedList = new LinkedList();
    ageList = new LinkedList();
  }

  public Cache(int maxSize) {
    this();
    this.maxSize = maxSize;
  }

  public Cache(long maxLifetime) {
    this();
    this.maxLifetime = maxLifetime;
  }

  public Cache(int maxSize, long maxLifetime) {
    this();
    this.maxSize = maxSize;
    this.maxLifetime = maxLifetime;
  }

  public int getSize() {
    return size;
  }

  public int getMaxSize() {
    return maxSize;
  }

  public void setMaxSize(int maxSize) {
    this.maxSize = maxSize;
    // It's possible that the new max size is smaller than our current cache
    // size. If so, we need to delete infrequently used items.
    cullCache();
  }

  public synchronized int getNumElements() {
    return cachedObjectsHash.size();
  }

  public synchronized void add(Object key, Cacheable object) {
    // Delete an old entry if it exists.
    remove(key);

    int objectSize = object.getSize();
    // If the object is bigger than the entire cache, simply don't add it.
    if (objectSize > maxSize * .90) {
      return;
    }
    size += objectSize;
    CacheObject cacheObject = new CacheObject(object, objectSize);
    cachedObjectsHash.put(key, cacheObject);
    // Make an entry into the cache order list.
    LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);
    // Store the cache order list entry so that we can get back to it
    // during later lookups.
    cacheObject.lastAccessedListNode = lastAccessedNode;
    // Add the object to the age list
    LinkedListNode ageNode = ageList.addFirst(key);
    // We make an explicit call to currentTimeMillis() so that total accuracy
    // of lifetime calculations is better than one second.
    ageNode.timestamp = System.currentTimeMillis();
    cacheObject.ageListNode = ageNode;

    // If cache is too full, remove least used cache entries until it is
    // not too full.
    cullCache();
  }

  public synchronized Cacheable get(Object key) {
    // First, clear all entries that have been in cache longer than the
    // maximum defined age.
    deleteExpiredEntries();

    CacheObject cacheObject = (CacheObject) cachedObjectsHash.get(key);
    if (cacheObject == null) {
      // The object didn't exist in cache, so increment cache misses.
      cacheMisses++;
      return null;
    }

    // The object exists in cache, so increment cache hits.
    cacheHits++;

    // Remove the object from it's current place in the cache order list,
    // and re-insert it at the front of the list.
    cacheObject.lastAccessedListNode.remove();
    lastAccessedList.addFirst(cacheObject.lastAccessedListNode);

    return cacheObject.object;
  }

  public synchronized void remove(Object key) {
    CacheObject cacheObject = (CacheObject) cachedObjectsHash.get(key);
    // If the object is not in cache, stop trying to remove it.
    if (cacheObject == null) {
      return;
    }
    // remove from the hash map
    cachedObjectsHash.remove(key);
    // remove from the cache order list
    cacheObject.lastAccessedListNode.remove();
    cacheObject.ageListNode.remove();
    // remove references to linked list nodes
    cacheObject.ageListNode = null;
    cacheObject.lastAccessedListNode = null;
    // removed the object, so subtract its size from the total.
    size -= cacheObject.size;
  }

  /**
   * Clears the cache of all objects. The size of the cache is reset to 0.
   */
  public synchronized void clear() {
    Object[] keys = cachedObjectsHash.keySet().toArray();
    for (int i = 0; i < keys.length; i++) {
      remove(keys[i]);
    }

    // Now, reset all containers.
    cachedObjectsHash.clear();
    cachedObjectsHash = new HashMap(103);
    lastAccessedList.clear();
    lastAccessedList = new LinkedList();
    ageList.clear();
    ageList = new LinkedList();

    size = 0;
    cacheHits = 0;
    cacheMisses = 0;
  }

  public Object[] keys() {
    return cachedObjectsHash.keySet().toArray();
  }

  public Object[] values() {
    Object[] cacheObjects = cachedObjectsHash.values().toArray();
    Object[] values = new Object[cacheObjects.length];
    for (int i = 0; i < cacheObjects.length; i++) {
      values[i] = ( (CacheObject) cacheObjects[i]).object;
    }
    return values;
  }

  public long getCacheHits() {
    return cacheHits;
  }

  public long getCacheMisses() {
    return cacheMisses;
  }

  private final void deleteExpiredEntries() {
    //Check if expiration is turned on.
    if (maxLifetime <= 0) {
      return;
    }

    // Remove all old entries. To do this, we remove objects from the end
    // of the linked list until they are no longer too old. We get to avoid
    // any hash lookups or looking at any more objects than is strictly
    // neccessary.
    LinkedListNode node = ageList.getLast();
    //If there are no entries in the age list, return.
    if (node == null) {
      return;
    }

    // Determine the expireTime, which is the moment in time that elements
    // should expire from cache. Then, we can do an easy to check to see
    // if the expire time is greater than the expire time.
    long expireTime = currentTime - maxLifetime;

    while (expireTime > node.timestamp) {
      // Remove the object
      remove(node.object);

      // Get the next node.
      node = ageList.getLast();
      // If there are no more entries in the age list, return.
      if (node == null) {
        return;
      }
    }
  }

  private final void cullCache() {
    // See if the cache size is within 3% of being too big. If so, clean out
    // cache until it's 10% free.
    if (size >= maxSize * .97) {
      // First, delete any old entries to see how much memory that frees.
      deleteExpiredEntries();
      int desiredSize = (int) (maxSize * .90);
      while (size > desiredSize) {
        // Get the key and invoke the remove method on it.
        remove(lastAccessedList.getLast().object);
      }
    }
  }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -