我有一个缓存,可以预先加载大量数据(通过后台线程),并且在完全之前无法使用(它也会经常重新加载并在该加载期间无法使用)。我希望使用它的类在访问之前检查标志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()将失败?我是否应该打扰标志和jut捕获异常(因为我基本上做了相同的代码,如果抛出异常,就好像标志是假的)。我只是觉得我做了一些稍微错误的事情,但我不能指责它。感谢。
答案 0 :(得分:2)
我真的需要try / catch吗?是吗 国旗将永远是可能的 设置为false并且readLock尝试() 会失败吗?
是的,你需要它。在调用时间cache.isLoaded()
和cache.get()
之间,作者可以进入并获得写锁定 - 在这种情况下,cache.isLoaded()
将返回true
,但是cache.get()
将抛出异常。
我是否应该打扰国旗和 jut捕获异常(因为我 如果是,基本上做相同的代码 抛出异常就像标志一样 假)。
从您显示的代码中,仅在get
无法获取读锁定的情况下抛出异常。只有当时有并发写入器时,才会获取读锁定失败。在这种情况下,isLoaded
也会返回false。所以仅仅依靠异常就足够了。另外,请考虑创建专门的CacheStaleException
。
答案 1 :(得分:1)
如果某个其他线程已经获得该锁,则tryLock
将失败。这通常意味着如果客户端由于高争用而无法获取锁(多个客户端访问相同的缓存),则会抛出异常。您是否在客户层中实施了处理此类情况的后备策略?
另外,为什么static
会锁定?我认为即使您的缓存通常在应用程序中用作单例,也不需要通过使Locks静态来限制其可用性。
答案 2 :(得分: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;
}