我在工作中遇到了这个难题,想看看是否有更好的解决方案……感觉应该有一个更简单、更清晰的答案。
目标:在键级别而非整个 map 级别并发访问带锁的 map ,以确保原子性,同时尽可能减少对性能的影响。
我有一个需要并发的 map 。 *(添加)随着时间的推移, map 将充满未知数量的条目。我有多个读者和一个作家。作者执行“先检查后放置”,读者执行简单的 get()。我需要这些是原子的……但仅限于关键级别。因此,例如,如果读者正在检查 key X,而作者正在写入 key Y,我不在乎我是否错过了对 key Y 的写入。如果读者/作者正在使用同一个 key ,但是我需要那是原子的。
最简单的解决方案是锁定整个 map 。但这似乎会影响性能,因为大约有 10,000 个键最终会出现在 map 中。 (如果这看起来不会因为 Map 的大小相对较小而影响性能,那么为了论证起见,我们假设 Map 有更多的键。)
据我所知,ConcurrentHashMap 不会保证我需要的“每个键”原子行为。
想到的下一个解决方案是拥有一个锁对象数组。您将根据原始 key 的散列索引到该锁 Object()
数组中。这仍然会有一些争论,因为你拥有的锁少于你拥有原始 map 的 key 。我知道 ConcurrentHashMap 在后台( strip 化)做了类似的事情来提供并发性(但不是原子性)。
是否有更简单的方法来执行这种类型的单键或 strip 锁定?
谢谢。
最佳答案
当值(value)生成是一个耗时的过程时,就会出现这种担忧。您不想锁定整个 map 并找到缺失值,并在生成值时保持 map 锁定。您可以在生成期间释放 map ,但是您可能会同时发生两次未命中和生成。
不是直接用键存储值,而是将其存储在引用对象中:
public class Ref<T>
{
private T value;
public T getValue()
{
return value;
}
public void setValue(T value)
{
this.value = value;
}
}
因此,如果您最初拥有 Map<String, MyThing>
的 map ,您改为使用 Map<String, Ref<MyThing>>
.不要为并发实现而烦恼,只需使用 HashMap 或 LinkedHashMap 或其他任何东西。
现在您可以锁定 map 以查找或创建引用持有人,然后释放 map 。之后,您可以锁定引用以查找或创建值对象:
String key; // key you're looking up
Map<String, Ref<MyThing>> map; // the map
// Find the reference container, create it if necessary
Ref<MyThing> ref;
synchronized(map)
{
ref = map.get(key);
if (ref == null)
{
ref = new Ref<MyThing>();
map.put(key, ref);
}
}
// Map is released at this point
// Now get the value, creating if necessary
MyThing result;
synchronized(ref)
{
result = ref.getValue();
if (result == null)
{
result = generateMyThing();
ref.setValue(result);
}
}
// result == your existing or new object
关于java - 在 Map 中实现按键或 strip 锁定 - 最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21082875/