【发布时间】:2017-06-22 01:18:50
【问题描述】:
通常我会锁定一个关键部分,如下所示。
public class Cache {
private Object lockObject = new Object();
public Object getFromCache(String key) {
synchronized(lockObject) {
if (cache.containsKey(key)) {
// key found in cache - return cache value
}
else {
// retrieve cache value from source, cache it and return
}
}
}
}
我的想法是避免可能导致数据源被多次命中并且键被多次添加到缓存中的竞争条件。
现在,如果两个线程几乎同时进入 不同 缓存键,我仍然会阻止一个。
假设钥匙是唯一的 - 通过锁定钥匙,锁仍然可以工作吗?
我认为它不会起作用,因为我知道对象引用应该相同才能使锁生效。我想这归结为它如何检查相等性。
public class Cache {
public Object getFromCache(String key) {
synchronized(key) {
if (cache.containsKey(key)) {
// key found in cache - return cache value
}
else {
// retrieve cache value from source, cache it and return
}
}
}
}
【问题讨论】:
-
没有。您需要保护的资源是缓存,而不是密钥。你的建议没有意义。
-
通常,密钥会散列到锁定对象数组中以避免实例问题。这称为条带化,其中条带(资源)受到此锁的保护,不会发生任何突变。在您的缓存示例中,这称为记忆化以避免cache stampede,通过锁定内部哈希表条目来完成。为了避免锁定读取,这将使用乐观获取和回退(双重检查锁定)。 Caffeine 和其他缓存实现了这种技术。
-
感谢 Ben,您的解释很有用。我将介绍一个散列在密钥上的锁数组。
标签: java concurrency thread-safety