Java中的ConcurrentHashMap困境

Java中的ConcurrentHashMap困境,java,concurrency,hashmap,Java,Concurrency,Hashmap,CocncurrentHashMap提供了一种方法,可以通过putIfAbsent方法自动检查并添加元素(如果该元素不存在),如下例所示 xmlObject = new XMLObejct(xmlId); mapOfXMLs.putIfAbsent(xmlId, xmlObject); 然而,我的困境是,我必须提前创建xmlObject。是否有一种方法可以在密钥当前检查后推迟对象创建 我希望下面三件事都能原子化地发生 检查钥匙是否存在 如果密钥不存在,则创建对象 添加要映射的对象 我知道我可以

CocncurrentHashMap
提供了一种方法,可以通过
putIfAbsent
方法自动检查并添加元素(如果该元素不存在),如下例所示

xmlObject = new XMLObejct(xmlId);
mapOfXMLs.putIfAbsent(xmlId, xmlObject);
然而,我的困境是,我必须提前创建
xmlObject
。是否有一种方法可以在密钥当前检查后推迟对象创建

我希望下面三件事都能原子化地发生

  • 检查钥匙是否存在
  • 如果密钥不存在,则创建对象
  • 添加要映射的对象

  • 我知道我可以使用
    synchronized
    块来实现这一点,如果我使用的是synchronized块,为什么要使用
    CocurrentHashMap

    番石榴缓存提供了这样的功能(),尽管它有些隐藏


    如果您已经可以使用Java8,那么您可以使用。但我想如果你能使用它,你就不会问……

    标准的、近乎完美的模式是:

    Foo foo = map.get(key);
    if(foo == null) {
        map.putIfAbsent(new Foo());
        foo = map.get(key);
    }
    

    它有时确实会产生一个额外的对象,但非常罕见,因此从性能的角度来看,这当然是好的。只有在构建插入到数据库中的对象或向用户或其他人收费时,这才是不好的。

    我已经多次遇到过这种情况,他们允许延迟创建值。它可能不适用于您的用例,但如果适用,这基本上就是我所做的:

    static abstract class Lazy<T> {
    
        private volatile T value;
    
        protected abstract T initialValue();
    
        public T get() {
            T tmp = value;
            if (tmp == null) {
                synchronized (this) {
                    tmp = value;
                    if (tmp == null)
                        value = tmp = initialValue();
                }
            }
            return tmp;
        }
    }
    
    static ConcurrentHashMap<Integer, Lazy<XmlObject>> map = new ConcurrentHashMap<>();
    
    其用法是:

        final int id = 1;
    
        map.putIfAbsent(id, new LazyXmlObject(id));
    
        System.out.println(map.get(id).get());
    

    您想在创建对象之前检查对象是否作为键存在?为什么不使用
    Future
    s作为值呢?如果您的典型用例中存在重复对象创建的问题?@fge这是可行的,但我发现错误的未来实现具有
    get()
    这太慢了,您最好对ConcurrentMap的写入操作使用双重检查锁定。@Puru--这在
    未来的合同中;一旦计算结束,结果将被保留(直到对
    未来的引用当然不在范围内)42这正是我目前拥有的,我试图看看是否可以用并发hashmapNo替换它,它不是你所拥有的。在您的例子中,您可以多次创建XmlObject,在我的例子中,最多只创建一次。不,我在代码中介绍的是如何在不使用双重检查锁定习惯用法的情况下高效地使用
    ConcurrentHashmap
    。我目前在代码中使用双重检查锁定。这一点都不明显。无论如何,快乐编码:)
    static class LazyXmlObject extends Lazy<XmlObject> {
        private final int id;
    
        public LazyXmlObject(int id) {
            super();
            this.id = id;
        }
    
        @Override
        protected XmlObject initialValue() {
            return new XmlObject(id);
        }
    }
    
        final int id = 1;
    
        map.putIfAbsent(id, new LazyXmlObject(id));
    
        System.out.println(map.get(id).get());