【问题标题】:Map allowing to putIfAbsent without creating the value when key already exists映射允许 putIfAbsent 在键已经存在时不创建值
【发布时间】:2012-04-26 21:32:20
【问题描述】:

我想使用与ConcurrentMap 等效的映射(我想要与 putIfAbsent 方法等效的映射),但这不会强迫我事先创建对象。

例如当我这样做时:

m.putIfAbsent( key, new CyclingArray() );

我最终可能会创建一个新的 CyclingArray(不管是什么)对象。

当然,我知道我可以锁定整个地图,但这将打败ConcurrentMap 的全部意义。

在概念上可以像下面这样工作吗?

   m.putIfAbsent( key, new Callback<CyclingArray>() {
     @Override
     public CyclingArray provide() {
       return new CyclingArray();  // only called if the key wasn't already present
     }         
   }

您是否知道任何提供地图的图书馆:

  1. 提供类似于 ConcurrentMap 提供的“接口”,包括 putIfAbsent 方法。
  2. 只锁定我们将要使用的段(例如,ConcurrentHashMap 实现)
  3. 允许选择性地创建值,当且仅当键不存在时,从而避免无用的垃圾生成。
  4. 不强迫我先使用 containsKey,然后使用 putIfAbsent,因为这在某种程度上也违背了 putIfAbsent 的目的。

请注意,我不是询问是否可以使用 ConcurrentMap 完成上述示例(它不能 AFAIK)。

我正在考虑扩展 ConcurrentHashMap 并使用回调版本重载 putIfAbsent,但遗憾的是 ConcurrentHashMap 在内部使用了最终的 Segment 类。

在重新发明轮子之前,我想知道是否有任何地图已经提供了类似的功能。

【问题讨论】:

    标签: java concurrency map garbage


    【解决方案1】:

    这是您正在寻找的一个常见用例,称为 memoization。我会看MapMaker

    您将能够创建一个 computingMap 并将您的创建函数放在那里:

     ConcurrentMap<Key, CyclingArray> graphs = new MapMaker()
           .concurrencyLevel(32)
           .makeComputingMap(
               new Function<Key, CyclingArray>() {
                    public CyclingArray  apply(Key key) {
                        return new CyclingArray();  // only called if the key wasn't already    
                    }              
               });
    

    这里只有Key 不存在时才会调用Function

    而且我知道 Java 未来的计划是标准 Java 会附带一个 ComputingMap 类型接口,不幸的是,此时您将不得不委托给 google-collections。

    【讨论】:

    • +1... 但我一直使用术语“memoization”来指代方法调用的 results 动态缓存:compute(17 ,24,59) 需要很长时间来执行,将该计算的结果存储在缓存中并在缓存命中时重用。在试图防止不必要的对象创建时,我从未听说过使用“记忆”一词。在 Wikipedia en.wikipedia.org/wiki/Memoization 上,定义和示例与对象创建无关。我可能弄错了,但我觉得将其称为“记忆”有点奇怪:)
    • 要明确一点:在这里使用回调来避开对象创建本质上是围绕 Java“特性”工作的(让我们这样称呼它)。因此,确实我们最终可能或多或少地重用方法调用的结果,但在我的想法中,记忆始终是关于使用方法调用的参数来即时计算密钥并将结果存储在缓存中(与动态编程相反,动态编程通常会提前缓存所有可能的结果)。
    猜你喜欢
    • 2018-01-15
    • 2017-05-19
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2018-04-22
    • 2020-07-31
    • 2019-03-05
    • 2017-11-03
    相关资源
    最近更新 更多