最小阻塞缓存存储
Minimal blocking cache store
假设我们有不同的方法来执行一些 http 调用,每个方法都用一些特定的参数调用...我们想比较方法 + 参数的最后一个值,看看响应是否不同,然后才继续。 ..
method1(Arg arg)
method2(Arg arg)
当我们进行特定调用时,我们有响应的哈希值,以便我们可以将它们放入映射中...
{"key" : "method1|arg", "value" : "hash"}
现在,下次我们收到响应时,我们会从该缓存存储中检索这个特定的 "hash" 并进行比较...
但是所有方法|arg 调用都是并发的,并且可能有许多相同组合的调用并行 运行,只有并发问题可能发生在入门级别...当相同的调用尝试时在另一个正在更新时更新缓存或读取...
所以我们需要在一个入口对象上同步,这样我们就只有 "method|arg" 的唯一完全相同的组合才能阻止它......只有相同的调用才能阻止它的其他执行,并且不会阻止与它无关的其他调用。
我想知道是否有用于此目的的库(缓存)?
如果没有,那么是否有任何 Map 实现可以通过 key 获取 Entry?或者我再保留一张地图?
通常使用 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;
}
}
}
如果您发现可能存在的错误,请发表评论:)
我想你可以 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
块之前为同一键设置了一个值。
假设我们有不同的方法来执行一些 http 调用,每个方法都用一些特定的参数调用...我们想比较方法 + 参数的最后一个值,看看响应是否不同,然后才继续。 ..
method1(Arg arg)
method2(Arg arg)
当我们进行特定调用时,我们有响应的哈希值,以便我们可以将它们放入映射中...
{"key" : "method1|arg", "value" : "hash"}
现在,下次我们收到响应时,我们会从该缓存存储中检索这个特定的 "hash" 并进行比较...
但是所有方法|arg 调用都是并发的,并且可能有许多相同组合的调用并行 运行,只有并发问题可能发生在入门级别...当相同的调用尝试时在另一个正在更新时更新缓存或读取...
所以我们需要在一个入口对象上同步,这样我们就只有 "method|arg" 的唯一完全相同的组合才能阻止它......只有相同的调用才能阻止它的其他执行,并且不会阻止与它无关的其他调用。
我想知道是否有用于此目的的库(缓存)?
如果没有,那么是否有任何 Map 实现可以通过 key 获取 Entry?或者我再保留一张地图?
通常使用 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;
}
}
}
如果您发现可能存在的错误,请发表评论:)
我想你可以 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
块之前为同一键设置了一个值。