[英]Using ReentrantReadWriteLock and a boolean flag
我有一个缓存,该缓存预先由大量数据(通过后台线程)加载,并且直到满时才可用(它还会经常重新加载,并且在该加载期间不可用)。 我希望使用它的类在访问之前检查标志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()将失败? 我是否应该还要烦恼该标志并突出捕获Exception(因为如果抛出Exception就像标志为false一样,我基本上会执行相同的代码)。 我只是觉得自己做错了点什么,但我不能指责它。 谢谢。
我真的需要try / catch吗? 是否有可能将标志设置为false并且readLock try()将失败?
是的,您需要它。 在cache.isLoaded()
和cache.get()
的时间之间,编写者可以进入并获得写锁-在这种情况下, cache.isLoaded()
将返回true
,但是cache.get()
将引发异常。
我是否应该还要烦恼该标志并突出捕获Exception(因为如果抛出Exception就像标志为false一样,我基本上会执行相同的代码)。
从显示的代码中,仅在get
无法获取读取锁的情况下才会引发异常。 仅当同时存在并发写入器时,读取锁定的获取失败。 在这种情况下, isLoaded
也将返回false。 因此,仅依靠异常就足够了。 另外,考虑创建专门的CacheStaleException
。
如果其他某个线程已经获取了该锁,则tryLock
将失败。 这通常意味着,如果客户端由于争用率较高(多个客户端访问同一缓存)而无法获取锁,则会引发异常。 您在客户端层实施了任何可解决此类情况的后备策略吗?
另外,为什么要使用static
锁? 我认为,即使您的缓存通常在应用程序中作为单例使用,也无需通过将Locks设置为静态来限制其可用性。
不,但是老实说,您的范例令人困惑。 假定转到实际数据库很昂贵,这就是缓存的目的。 在重新加载缓存的情况下,仅等待直到重新缓存就更好了吗?
假设您确实确实想在读取锁不立即可用的情况下转到数据库,我可以这样做:
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.