使用 ReentrantReadWriteLock 和布尔标志

发布于 2024-10-06 11:24:45 字数 1254 浏览 5 评论 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() 将失败?我是否应该打扰该标志并捕获异常(因为如果抛出异常,就像标志为假一样,我基本上会执行相同的代码)。我只是觉得我做的事情有点不对劲,但又说不出来。谢谢。

I have a cache that gets loaded upfront with a large amount of data (by a background thread) and is unusable until full (it will also get reloaded every so often and be unusable during that load). I want the classes that use it to check a flag isLoaded() before accesses. I use a ReentrantReadWriteLock (I omit this in the code for simplicity) for access control like this:

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;
      }
   }
....
}  

Now in my other class I have a block like this:

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

Do I really need the try/catch? Is it ever possible that the flag will be set to false and the readLock try() will fail? Should I even bother with the flag and jut catch the Exception (since I basically do the same code if the Exception is thrown as if the flag is false). I just feel like I am doing something slightly wrong but I can't put my finger on it. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

書生途 2024-10-13 11:24:45

我真的需要 try/catch 吗?是吗
国旗永远有可能
设置为 false 并且 readLock try()
会失败吗?

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

我应该为国旗而烦恼吗?
只需捕获异常(因为我
基本上执行相同的代码,如果
抛出异常,就像标志一样
错误)。

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

Do I really need the try/catch? Is it
ever possible that the flag will be
set to false and the readLock try()
will fail?

Yes, you need it. Between the time cache.isLoaded() and cache.get() are called, a writer can come in and get the write lock - in which case cache.isLoaded() will return true, but cache.get() will throw the exception.

Should I even bother with the flag and
jut catch the Exception (since I
basically do the same code if the
Exception is thrown as if the flag is
false).

From the code you have shown, the exception is thrown only in cases where the get fails to acquire the read lock. Acquisition of the read lock fails only if there is a concurrent writer at the time. isLoaded also returns false in precisely this scenario. So just relying on the exception would suffice. Also, consider creating a specialized CacheStaleException.

Saygoodbye 2024-10-13 11:24:45

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

另外,为什么要使用静态锁?我认为即使您的缓存通常在应用程序中作为单例使用,也无需通过将锁设为静态来限制其可用性。

The tryLock will fail if some other thread has already acquired that lock. This typically means that an exception would be thrown if a client fails to acquire a lock due to high contention (multiple clients accessing the same cache). Is there any fallback strategy you have implemented in your client layer which deals with such situations?

Also, why static locks? I think that even though your cache is typically used in the application as a singleton, there is no need to limit its usability by making Locks static.

纸伞微斜 2024-10-13 11:24:45

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

假设如果读锁不能立即可用,您确实想要访问数据库,我会这样做:

   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;
   }

No, but to be honest your paradigm is confusing. Presumably it is expensive to go to the actual database and that is the purpose of the cache. In the case that the cache is being reloaded, is it not better to just wait until it is?

Assuming you really do want to go to the database if the read lock is not immediately available, I would do this:

   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;
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文