使用 ReentrantReadWriteLock 和布尔标志
我有一个缓存,它预先加载了大量数据(通过后台线程),并且在满之前不可用(它也会经常重新加载,并且在加载期间不可用)。我希望使用它的类在访问之前检查标志 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,你需要它。在调用
cache.isLoaded()
和cache.get()
之间,写入者可以进入并获取写锁 - 在这种情况下cache. isLoaded()
将返回true
,但cache.get()
将抛出异常。从您显示的代码来看,仅在
get
无法获取读锁的情况下才会引发异常。仅当当时有并发写入时,获取读锁才会失败。在这种情况下,isLoaded
也会返回 false。所以仅仅依赖异常就足够了。另外,请考虑创建一个专门的CacheStaleException
。Yes, you need it. Between the time
cache.isLoaded()
andcache.get()
are called, a writer can come in and get the write lock - in which casecache.isLoaded()
will returntrue
, butcache.get()
will throw the exception.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 specializedCacheStaleException
.如果其他线程已经获取了该锁,
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.不,但说实话,你的范例令人困惑。据推测,访问实际数据库的成本很高,这就是缓存的目的。在缓存正在重新加载的情况下,等待它加载不是更好吗?
假设如果读锁不能立即可用,您确实想要访问数据库,我会这样做:
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: