0

我有一个缓存,它预先加载了大量数据(通过后台线程)并且在满之前无法使用(它也会经常重新加载并且在加载期间无法使用)。我希望使用它的类isLoaded()在访问之前检查标志。我使用 ReentrantReadWriteLock (为了简单起见,我在代码中省略了它)进行访问控制,如下所示:

public class Cache {

   private volatile boolean loaded = false; //starts false

   private static String[] cache;

   private static Lock readLock;
   private static Lock writeLock;

   public Object get(Object key) {
       if (!readLock.tryLock()) throw IllegalStateException(...);
       try {
           ... do some work
       } finally {
           readLock.unlock();
       }
   }

   // called by background thread
   private void loadFull() {
      loaded = false;
      writeLock.lock()
      try {
          cache = new String[];
          ... fill cache
      } finally {
          writeLock.unlock();
          loaded = true;
      }
   }
....
}  

现在在我的另一堂课中,我有一个这样的块:

if (cache.isLoaded()) {
    try {
      Object x = cache.get(y);
    } catch (IllegalStateException iex) {
      // goto database for object
    }
} else {
    // goto database for object
}

我真的需要try/catch吗?标志是否有可能设置为 false 并且 readLock try() 会失败?我是否应该为标志而烦恼并抓住异常(因为如果抛出异常,就好像标志为假一样,我基本上会执行相同的代码)。我只是觉得我做错了什么,但我不能把手指放在上面。谢谢。

4

3 回答 3

2

我真的需要try/catch吗?标志是否有可能设置为 false 并且 readLock try() 会失败?

是的,你需要它。在调用cache.isLoaded()cache.get()之间,写者可以进来并获得写锁——在这种情况下cache.isLoaded()会返回true,但cache.get()会抛出异常。

我是否应该为标志而烦恼并抓住异常(因为如果抛出异常,就好像标志为假一样,我基本上会执行相同的代码)。

get从您显示的代码中,只有在无法获取读取锁的情况下才会引发异常。仅当当时有并发写入者时,读取锁的获取才会失败。isLoaded在这种情况下也返回 false。所以仅仅依靠例外就足够了。另外,考虑创建一个专门的CacheStaleException.

于 2010-12-07T19:16:39.640 回答
1

tryLock如果某个其他线程已经获得了该锁,则该操作将失败。这通常意味着如果客户端由于高争用(多个客户端访问同一个缓存)而无法获取锁,则会引发异常。您是否在客户端层中实施了任何后备策略来处理这种情况?

还有,为什么要static锁?我认为即使您的缓存通常在应用程序中作为单例使用,也没有必要通过将 Locks 设为静态来限制其可用性。

于 2010-12-07T18:44:17.297 回答
0

不,但老实说,您的范式令人困惑。据推测,访问实际数据库的成本很高,这就是缓存的目的。在缓存被重新加载的情况下,等待它不是更好吗?

假设如果读锁不是立即可用,你真的想去数据库,我会这样做:

   public Object get(Object key) {
       Object returnValue;
       if (readLock.tryLock()) {
           try {
               ... do some work
               returnValue = ...
           } finally {
               readLock.unlock();
           }
       } else {
           //go to database
           returnValue = ...
       }
       return returnValue;
   }
于 2010-12-07T19:01:32.863 回答