Об использовании Singleton на основе Enum для кэширования больших объектов (Java) - PullRequest
1 голос
/ 19 июля 2009

Есть ли лучший способ кэшировать некоторые очень большие объекты, которые могут быть созданы только один раз, и поэтому должны быть кэшированы? В настоящее время у меня есть следующее:

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);
    }
}  

Есть несколько классов, которые могут использовать LargeObjects, поэтому я решил использовать синглтон для кэша, вместо того, чтобы передавать LargeObjects каждому классу, который его использует.

Кроме того, карта не содержит много ключей (один или два, но ключ может отличаться в разных запусках программы), поэтому есть ли другая, более эффективная карта для использования в этом случае?

Ответы [ 2 ]

4 голосов
/ 19 июля 2009

Вам может потребоваться защита потоков, чтобы у вас не было двух экземпляров с одинаковыми именами. Это имеет большое значение для небольших карт, но вы можете избежать одного вызова, который может сделать его быстрее.

public LargeObject get(String s) {  
    synchronized(map) {
        LargeObject ret = map.get(s);
        if (ret == null) 
            map.put(s, ret = new LargeObject(s));
        return ret;
    }
}
2 голосов
/ 19 июля 2009

Как уже указывалось, вам необходимо обратиться к безопасности потоков. Простое использование 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;
    }
}

Вам нужно использовать его именно в этой форме, чтобы иметь правильное и наиболее эффективное поведение.

Если вы должны убедиться, что только один поток может даже создать экземпляр значения для данного ключа, тогда возникает необходимость обратиться к чему-то вроде карты вычислений в Google Collections или к примеру с памяткой в ​​книге Брайана Гетца «Параллелизм Java на практике» .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...