java - 一个键具有多个值的并发映射,并在超时时自动删除

标签 java multithreading dictionary concurrency guava

我是并发领域的新手。我读到有关 Guava 的信息CacheMultiMap 。我寻找能够结合两者的一些可能性的东西:

  1. 来自 Cache我希望在 ACCESS_TIMEOUT 和 WRITE_TIMEOUT 过期后自动删除。
  2. 来自 Multimap我想要多个值与一个键关联。
  3. 所有这些都必须同时进行。
  4. 我有多个作者和多个读者。我想用随机键添加值并删除它们。

问题:是否有适合我需求的 map 实现?

更新:Striped<Lock>解决方案

我读到的更多内容 Striped<Lock> - 对我来说更有吸引力。但这在我脑海中引发了更多问题:

  1. 如果我使用类似Striped<Lock>的东西与 Guava Cache已经使用 ConcurrentHashMap我可以面对死锁或性能下降的问题。我错了吗?
  2. 如果我使用Striped<Lock>超过Cache它仍然没有消除与每个键多个值相关的问题。
  3. Striped<Lock>在我的情况下消除使用并发​​映射的需要? (我想答案是肯定的)但在 GitHub 上却看到了相反的情况。

最佳答案

您可以从 Cache<SomeKey, Collection<SomeValue>> 开始(因此您仍然会过期)并使用同步集合( Collections.synchronized*() )作为值。

但这里真正的问题是您需要对集合进行并发访问的类型:

  • 操作同步就足够了,这样集合就不会被损坏,还是您需要更高级别的语义,例如 ConcurrentMap.putIfAbsent()优惠?
  • 您需要以原子方式对值集合执行多个操作吗?就像您需要做的那样

    if (c.contains(v)) {
        c.remove(v);
    } else {
        c.add(v);
    }
    

    你通常想把它放入synchronized(c) { }阻止。

如果是这样,您可能希望将集合包装在一个类中,公开这些高级语义并管理多个操作的锁以获得所需的原子性,并使用该类作为值:Cache<SomeKey, SomeValuesContainer> .


正如评论中提到的, Striped<Lock> 可用于同步访问多个Cache s/ConcurrentHashMap无需施加单一锁定,即使在中等程度的争用情况下也会影响性能。

如果您需要多个Cache s/ConcurrentHashMap s,那就是:为什么不Peer s(或它的包装器)实际上包含该信息吗?

1。死锁,性能

Guava 的Cache类似于 ConcurrentHashMap ,但它不使用它。然而,两者的工作方式相同,都具有可以独立锁定的段,从而减少并发访问映射时(尤其是更新时)的争用。使用Striped<Lock>对任何一个的访问都不会导致死锁,只有当您没有以一致的顺序锁定多个锁时才会发生死锁:这在这里不会发生,因为您将始终锁定 Lock获取自Striped<Lock>在调用 Cache 之前或ConcurrentHashMap ,然后锁定其段(您看不到)。

至于性能,是的,锁定是有成本的,但这实际上取决于争用级别(可以使用 Striped<Lock> 中的 number of stripesconcurrencyLevel 中的 Cache 进行调整)。但是,无论如何,您都需要适当的并发支持,因为没有它,您可能会得到无效结果(或损坏数据),因此您必须做一些事情(使用锁定或 lock-free algorithm )。

2。每个键有多个值

我原来的答案仍然有效。从多个问题中很难准确地了解您到底想做什么(如果您能够在一个问题中提供完整、一致的上下文,那就更好了),但我认为 您只需要对每个键的多个值进行并发修改,因此同步集合应该足够了(但您至少需要这一点)。不过,在添加访问模式时,您必须对它们进行推理,以确保它们仍然适合模型:确保您的 replaceAll*() methods例如,锁定他们需要的东西。

3。是ConcurrentMap仍然需要 Striped<Lock>

是的!尤其是 Striped<Lock>与单个 Lock ,因为您仍然会获得不使用相同 strip 的键的并发更新(这就是 Striped<Lock> 的全部意义),因此您需要支持并发修改的数据结构。如果您使用简单的HashMap ,您很有可能在足够的负载下损坏它(例如,导致无限循环)。

关于java - 一个键具有多个值的并发映射,并在超时时自动删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22068772/

相关文章:

java - 如何在 Spring 进行模仿

java - Android studio setContentView(R.layout.activity_login);即使我的第二个 Activity 名称 Activity_login 出现在布局文件夹中也无法正常工作

java - 在Java中插入和读取字符串数组

Java 线程和内核数

c# - Win8 ComboBox IsDropDownOpen + 可见性导致 UI 出现故障

java - 读取和丢弃数据 CSV

iphone - 使用 MapKit 在 map 中的 pin(注释)标注中显示自定义 UIView

python - 将字典分组为可能的最小键值对集

c++ - 在 C++ 中显示字符串、vector<int> 映射

java - 在多线程环境下使用for循环避免ConcurrentModificationException