Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用基于枚举的单例缓存大型对象(Java)_Java_Design Patterns_Oop_Hashmap - Fatal编程技术网

使用基于枚举的单例缓存大型对象(Java)

使用基于枚举的单例缓存大型对象(Java),java,design-patterns,oop,hashmap,Java,Design Patterns,Oop,Hashmap,有没有更好的方法来缓存一些非常大的对象,这些对象只能创建一次,因此需要缓存?目前,我有以下几点: public enum LargeObjectCache { INSTANCE; private Map<String, LargeObject> map = new HashMap<...>(); public LargeObject get(String s) { if (!map.containsKey(s)) {

有没有更好的方法来缓存一些非常大的对象,这些对象只能创建一次,因此需要缓存?目前,我有以下几点:

public enum LargeObjectCache {  
    INSTANCE; 

    private Map<String, LargeObject> map = new HashMap<...>();

    public LargeObject get(String s) {  
        if (!map.containsKey(s)) {
            map.put(s, new LargeObject(s));
        }
        return map.get(s);
    }
}  
public enum LargeObjectCache{
实例;
私有映射映射=新的HashMap();
公共大对象获取(字符串s){
如果(!map.containsKey){
地图放置,新的大型对象;
}
返回地图。获取(s);
}
}  
有几个类可以使用LargeObject,这就是为什么我决定对缓存使用单例,而不是将LargeObject传递给每个使用它的类


此外,映射不包含许多键(一个或两个,但键在程序的不同运行中可能会有所不同),因此,在这种情况下,是否有另一个更有效的映射可供使用?

您可能需要线程安全性来确保没有两个同名实例。 这对小地图来说确实很重要,但您可以避免一次调用,这会使它更快

public LargeObject get(String s) {  
    synchronized(map) {
        LargeObject ret = map.get(s);
        if (ret == null) 
            map.put(s, ret = new LargeObject(s));
        return ret;
    }
}

您可能需要线程安全性来确保没有两个同名实例。 这对小地图来说确实很重要,但您可以避免一次调用,这会使它更快

public LargeObject get(String s) {  
    synchronized(map) {
        LargeObject ret = map.get(s);
        if (ret == null) 
            map.put(s, ret = new LargeObject(s));
        return ret;
    }
}

正如已经指出的,您需要解决线程安全问题。简单地使用Collections.synchronizedMap()并不能使其完全正确,因为代码需要复合操作。同步整个块是一种解决方案。然而,如果使用ConcurrentHashMap非常关键,那么它将导致更并发和可伸缩的行为

public enum LargeObjectCache {  
    INSTANCE; 

    private final ConcurrentMap<String, LargeObject> map = new ConcurrentHashMap<...>();

    public LargeObject get(String s) {
        LargeObject value = map.get(s);
        if (value == null) {
            value = new LargeObject(s);
            LargeObject old = map.putIfAbsent(s, value);
            if (old != null) {
                value = old;
            }
        }
        return value;
    }
}
public enum LargeObjectCache{
实例;
私有最终ConcurrentMap=新ConcurrentHashMap();
公共大对象获取(字符串s){
大对象值=map.get(s);
如果(值==null){
值=新的较大对象;
LargeObject old=映射。putIfAbsent(s,值);
如果(旧!=null){
价值=旧;
}
}
返回值;
}
}
你需要在这个表单中准确地使用它,以获得正确和最有效的行为


如果您必须确保只有一个线程能够实例化给定键的值,那么就有必要求助于类似Google Collections中的计算地图或Brian Goetz的书《Java并发性在实践中》中的记忆器示例。

正如已经指出的,您需要解决线程安全问题。简单地使用Collections.synchronizedMap()并不能使其完全正确,因为代码需要复合操作。同步整个块是一种解决方案。然而,如果使用ConcurrentHashMap非常关键,那么它将导致更并发和可伸缩的行为

public enum LargeObjectCache {  
    INSTANCE; 

    private final ConcurrentMap<String, LargeObject> map = new ConcurrentHashMap<...>();

    public LargeObject get(String s) {
        LargeObject value = map.get(s);
        if (value == null) {
            value = new LargeObject(s);
            LargeObject old = map.putIfAbsent(s, value);
            if (old != null) {
                value = old;
            }
        }
        return value;
    }
}
public enum LargeObjectCache{
实例;
私有最终ConcurrentMap=新ConcurrentHashMap();
公共大对象获取(字符串s){
大对象值=map.get(s);
如果(值==null){
值=新的较大对象;
LargeObject old=映射。putIfAbsent(s,值);
如果(旧!=null){
价值=旧;
}
}
返回值;
}
}
你需要在这个表单中准确地使用它,以获得正确和最有效的行为


如果您必须确保只有一个线程能够实例化给定键的值,那么就有必要求助于类似Google Collections中的计算地图或Brian Goetz的书《Java并发性实践》中的Memorizer示例。

您说得对,谢谢。然而,在javadoc上,它提到了线程安全性:“这通常是通过在自然封装映射的某个对象上进行同步来实现的。如果不存在这样的对象,则应该使用Collections.synchronizedMap方法“包装”映射。”。那么,使用synchronized(map)和Collections.synchronizedMap(map)甚至使用ConcurrentHashMap有什么区别呢?它们似乎都有相同的目标,但我想一定有差异。如果您使用
synchronizedMap
(甚至是
CuncurrentMap
),那么您可能会创建两次对象。在创建
LargeObject
的过程中,您可以锁定特定的密钥(比如使用
Future
),而不是锁定整个地图。但是,代码会变得更复杂。但是如果需要按需以原子方式创建实例,则putIfAbsend()的并发复合操作在大型对象上的成本非常高。如果使用synchronizedMap(),则可能存在一种竞争条件,即两个或多个线程锁定map.get(),多个线程执行map.put()每个操作都是线程安全的,但不是一对操作。你说得对,谢谢。然而,在javadoc上,它提到了线程安全性:“这通常是通过在自然封装映射的某个对象上进行同步来实现的。如果不存在这样的对象,则应该使用Collections.synchronizedMap方法“包装”映射。”。那么,使用synchronized(map)和Collections.synchronizedMap(map)甚至使用ConcurrentHashMap有什么区别呢?它们似乎都有相同的目标,但我想一定有差异。如果您使用
synchronizedMap
(甚至是
CuncurrentMap
),那么您可能会创建两次对象。在创建
LargeObject
的过程中,您可以锁定特定的密钥(比如使用
Future
),而不是锁定整个地图。但是,代码会变得更复杂。但是如果需要按需以原子方式创建实例,则putIfAbsend()的并发复合操作在大型对象上的成本非常高。如果使用synchronizedMap(),则可能存在一种竞争条件,即两个或多个线程锁定map.get(),多个线程执行map.put()每个操作都是线程安全的,但不是一对操作。