【问题标题】:Atomically ensuring a ConcurrentMap entry以原子方式确保 ConcurrentMap 条目
【发布时间】:2013-09-02 07:55:54
【问题描述】:

在 Java 中,我经常需要懒惰地获取 ConcurrentMap 的条目,仅在必要时创建。

例如我可能有

ConcurrentMap<String, AtomicReference<Something>> a = new ConcurrentHashMap<>();
ConcurrentMap<String, Something> b = new ConcurrentHashMap<>();

我想创建一个通用函数来完成这项工作,这样我就不会为每种类型重复自己the rather cumbersome double checking code

以下是我所能得到的:

<K, V, C extends V> V ensureEntry(ConcurrentMap<K, V> map, K key, Class<? super C> clazz) throws Exception {
    V result = map.get(key);
    if (result == null) {
        final V value = (V)clazz.newInstance();
        result = map.putIfAbsent(key, value);
        if (result == null) {
            result = value;
        }
    }
    return result;
}

然后我可以像这样使用它:

AtomicReference<Something> ref = ensureElement(a, "key", AtomicReference.class);
Something something = ensureElement(b, "another key", Something.class);

问题是:这个函数很脏,并且仍然有一个不安全的泛型类转换((V))。一个完全通用和更清洁的可能吗?也许在 Scala 中?

谢谢!

【问题讨论】:

  • 为什么你要Class&lt;? super C&gt; 而不是Class&lt;? extends V&gt;?如果你有有意义的上限,就不需要向下转换,整个事情都是类型安全的。
  • 您还应该考虑普通的旧synchronized,这将消除无锁方法所需的样板复核。如今,无锁计算与其说是一种有用的技术,不如说是一种流行语。它有其合法的应用程序,但今天肯定被过度使用了。
  • 它不能为泛型类型编译。在上面的示例中,类型 AtomicReference 没有扩展 AtomicReference。 的类似错误超级V>。
  • 但是Class&lt;? super C&gt; 仍然毫无意义,因为您将Class 用作生产者。如果你不能定义一个上限,那么你应该使用Class&lt;?&gt; 来达到同样的效果。
  • 您可以使用guava caches 吗?

标签: java generics concurrency


【解决方案1】:

使用 Java 8 lambda,以下是我能得到的最简单的..

<K, V> V ensureEntry(ConcurrentMap<K, V> map, K key, Supplier<V> factory) {
    V result = map.get(key);
    if (result == null) {
        V value = factory.get();
        result = map.putIfAbsent(key, value);
        if (result == null) {
            result = value;
        }
    }
    return result;
}

ConcurrentMap<String, AtomicReference<Object>> map = new ConcurrentHashMap<>();
ensureEntry(map, "key", () -> new AtomicReference<>());
// or
ensureEntry(map, "key", AtomicReference::new);

【讨论】:

    猜你喜欢
    • 2010-09-23
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 2019-07-15
    相关资源
    最近更新 更多