3

我们有一个简单但非常常用的缓存,由 ConcurrentHashMap 实现。现在我们要定期刷新所有值(例如,每 15 分钟)。

我想要这样的代码:

 private void regularCacheCleanup() {
        final long now = System.currentTimeMillis();
        final long delta = now - cacheCleanupLastTime;
        if (delta < 0 || delta > 15 * 60 * 1000) {
            cacheCleanupLastTime = now;
            clearCache();
        }
  }

除了应该是:

  • 线程安全
  • 如果不清除缓存,则非阻塞且性能极好
  • 除了 java.* 类之外没有依赖项(所以没有 Google CacheBuilder)
  • 坚如磐石;-)
  • 无法启动新线程

现在我想在 ThreadLocal 中实现一个短计时器。当此到期时,将以同步方式检查真实计时器。然而,这是一个非常多的代码,所以一个更简单的想法会很好。

4

1 回答 1

4

解决此问题的主流方法是使用一些计时器线程以指定的时间间隔刷新缓存。但是,由于您不需要创建新线程,我能想到的一种可能的实现是伪定时缓存刷新。基本上,我会在缓存访问器(put 和 get 方法)中插入检查,每次客户端使用此方法时,我都会在执行 put 或 get 操作之前检查缓存是否需要刷新。这是粗略的想法:

class YourCache {

  // holds the last time the cache has been refreshed in millis
  private volatile long lastRefreshDate;

  // indicates that cache is currently refreshing entries
  private volatile boolean cacheCurrentlyRefreshing;

  private Map cache = // Your concurrent map cache...

  public void put(Object key, Object element) {
    if (cacheNeedsRefresh()) {
      refresh();
    }
    map.put(key, element);
  }

  public Object get(Object key) {
    if (cacheNeedsRefresh()) {
      refresh();
    }
    return map.get(key);
  }

  private boolean cacheNeedsRefresh() {
    // make sure that cache is not currently being refreshed by some
    // other thread.
    if (cacheCurrentlyRefreshing) {
      return false;
    }
    return (now - lastRefreshDate) >= REFRESH_INTERVAL;
  } 

  private void refresh() {
    // make sure the cache did not start refreshing between cacheNeedsRefresh()
    // and refresh() by some other thread.
    if (cacheCurrentlyRefreshing) {
      return;
    }

    // signal to other threads that cache is currently being refreshed.
    cacheCurrentlyRefreshing = true;

    try {
      // refresh your cache contents here
    } finally {
       // set the lastRefreshDate and signal that cache has finished
       // refreshing to other threads.
       lastRefreshDate = System.currentTimeMillis();
       cahceCurrentlyRefreshing = false;
    }
  }
}

我个人不会考虑这样做,但如果你不想或不能创建计时器线程,那么这可能是你的一个选择。

Note that although this implementation avoids locks, it is still prone to duplicate refreshes due to race events. If this is ok for your requirements then it should be no problem. If however you have stricter requirements then you need to put locking in order to properly synchronise the threads and avoid race events.

于 2012-09-14T12:10:38.843 回答