假设我们有不同的方法来执行一些http调用,每个调用一些特定的参数...我们想要比较方法+参数的最后一个值,看看响应是否不同,然后继续...
method1(Arg arg)
method2(Arg arg)
当我们进行特定调用时,我们有一个响应的哈希值,以便我们可以将它们放在地图中...
{"key" : "method1|arg", "value" : "hash"}
现在我们下次获得响应时,我们从该缓存存储中检索此特定“哈希”并进行比较...
但所有方法| arg调用都是并发的,并且可能会有多个并行运行的相同组合的调用,并且只有并发问题可能发生在Entry级别...当同一个调用尝试更新缓存或读取时另一个正在更新......
所以我们需要在一个入口对象上进行同步,并且我们将只有一个唯一完全相同的“method | arg”组合可以阻止它...只有同一个调用才能阻止其他的执行,并且不会阻止与其无关的其他电话。
我想知道是否已经为此目的使用了lib(缓存)?
如果没有,那么是否有任何Map实现允许按键进入?或者我会保留另一张地图?
通常使用HashMap并在Entry对象上同步是安全的吗? (我真的不敢想象当HashMap重新发布并且某些并发获取正在执行时会发生什么......)
更新
这是我提出的实现......尽管ConcurrentHashMap可能涵盖了这种情况,但想法只是锁定一个条目而不是整个地图...(除了写入之外)
public class HashCache {
final HashMap<String, Holder> hashCache = new HashMap<>();
public boolean hasChanged(String key, Object hash) {
assert key != null && hash != null;
Holder holder = hashCache.get(key);
if (holder == null) {
synchronized (hashCache) {
hashCache.put(key, new Holder(hash));
}
return true; // first hash
} else {
synchronized (holder) {
if (Objects.equals(holder.object, hash)) {
return false; // hash not changed
} else {
holder.object = hash;
return true; // hash changed
}
}
}
}
private static class Holder {
Object object;
Holder(Object object) {
this.object = object;
}
}
}
如果你看到可能的错误,请评论:)
答案 0 :(得分:2)
我认为你对ConcurrentHashMap
没问题。我不相信你需要一个缓存,因为你不需要缓存响应,而是存储响应的哈希值。
ConcurrentHashMap
是一个高度优化的Map
,可以尽可能避免线程争用,特别是对于读取(我相信这与您的情况相符)。
你可以使用另一种方法,一旦从普通HashMap
获得它,就锁定每个条目,但我不认为这是值得的。我首先使用ConcurrentHashMap
进行测试,并且只有在行为与预期结果不同时才会更改实现。
修改强>
根据您的修改,我必须坚持建议您使用ConcurrentHashMap
。无论如何,如果由于某种原因你不能负担得起,我相信你应该在第一次把价值放在地图上时仔细检查:
public boolean hasChanged(String key, Object hash) {
assert key != null && hash != null;
Holder holder = hashCache.get(key);
if (holder == null) {
synchronized (hashCache) { // Double-check that value hasn't been changed
// before entering synchronized block
holder = hashCache.get(key);
if (holder == null) {
hashCache.put(key, new Holder(hash));
return true; // first hash
} // inner if
} // sync block
} // outer if
// No more else!
synchronized (holder) {
if (Objects.equals(holder.object, hash)) {
return false; // hash not changed
} else {
holder.object = hash;
return true; // hash changed
}
}
}
需要进行仔细检查,因为另一个帖子可能在您第一个get()
之后但在您输入synchronized
块之前为同一个键设置了值。