java - 在 Map 中实现按键或 strip 锁定 - 最佳方法?

标签 java multithreading map concurrency java-6

我在工作中遇到了这个难题,想看看是否有更好的解决方案……感觉应该有一个更简单、更清晰的答案。

目标:在键级别而非整个 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/

相关文章:

java - java 中 .equals() 方法的假设 - 比较对象的实例或对象的状态

c - Win Api-SetEvent和WaitForSingleObject,线程之间的内存同步

java - 更新没有 DBHelper 的数据

java - 变量未初始化,Void 方法无法返回值,无法解析为变量

android - Qt 5.7 for Android 主 C++ 线程不连续运行

c++ - 在映射中存储没有默认构造函数的不可复制对象 (C++11)

c++ - C++ 的标准映射插入语义的基本原理?

java - 如何在达到限制时通过删除最旧的条目来限制 map 的最大大小

java - Hibernate session 在初始提交失败后未刷新数据库中的数据

java - 查询 Facebook 时停止工作线程