1

一度しか作成できないため、キャッシュする必要がある非常に大きなオブジェクトをキャッシュするより良い方法はありますか? 現在、私は以下を持っています:

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 を使用するすべてのクラスに渡すのではなく、シングルトンをキャッシュに使用することにしました。

また、マップには多くのキーが含まれていません (1 つまたは 2 つですが、キーはプログラムの実行ごとに異なる可能性があります)。この場合に使用する別のより効率的なマップはありますか?

4

2 に答える 2

4

同じ名前のインスタンスが 2 つないようにするために、スレッド セーフが必要になる場合があります。これは小さなマップでは大きな問題ですが、1 回の呼び出しを避けることで高速化できます。

public LargeObject get(String s) {  
    synchronized(map) {
        LargeObject ret = map.get(s);
        if (ret == null) 
            map.put(s, ret = new LargeObject(s));
        return ret;
    }
}
于 2009-07-19T12:02:59.723 に答える
2

指摘されているように、スレッドセーフに対処する必要があります。Collections.synchronizedMap() を使用するだけでは、コードが複合操作を伴うため、完全に正しいとは言えません。ブロック全体を同期することが 1 つの解決策です。ただし、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;
    }
}

正確で最も効率的な動作を得るには、この形式で正確に使用する必要があります。

特定のキーの値をインスタンス化するスレッドが 1 つだけであることを確認する必要がある場合は、Google Collections のコンピューティング マップや、Brian Goetz の著書「Java Concurrency in Practice」の memoizer の例などに目を向ける必要があります。

于 2009-07-19T14:10:43.053 に答える