2009-07-19 6 views
1

非常に大きなオブジェクトを一度キャッシュする方法はありますか?一度しか作成できないため、キャッシュする必要がありますか?現在、私は次のようしている:大規模オブジェクトをキャッシュするためにEnumベースのシングルトンを使用する場合(Java)

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つ存在しないようにスレッドセーフティが必要な場合があります。 小さな地図では大したことですが、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; 
    } 
} 
+0

ありがとうございます。 しかし、これはスレッド安全性について言及しています。「これは通常、マップを自然にカプセル化するオブジェクトで同期することによって実現されます。オブジェクトが存在しない場合、Collections.synchronizedMapメソッドを使用してマップを " "。 同期(マップ)の使用とCollections.synchronizedMap(マップ)の使用の違い、またはConcurrentHashMap の使用の違いは何ですか?彼らはすべて同じ目標を持っているようですが、違いがなければならないと思います。 –

+0

'synchronizedMap'(あるいは' CuncurrentMap')を使うと、オブジェクトが2回作られることになります。 'LargeObject'の作成中にマップ全体をロックするのではなく、特定のキーをロックすることができます(例えば、' Future'を使って)。しかし、コードはより複雑になります。 –

+0

しかし、オンデマンドで原子的に作成されたインスタンスを必要とする場合、putIfAbsend()のコンカレント・コンパウンド操作はラージ・オブジェクトに対して非常にコストがかかります。 – akarnokd

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 = value.putIfAbsent(s, value); 
      if (old != null) { 
       value = old; 
      } 
     } 
     return value; 
    } 
} 

正しく正確な動作を行うには、このフォームで正確に使用する必要があります。

特定のキーの値をインスタンス化するスレッドが1つしかないようにする必要がある場合は、Google CollectionsのコンピューティングマップやBrian Goetzの著書「Java Concurrency in Practice "