4

キャッシュが AtomicReference として格納された単純なキャッシュを実装しています。

private AtomicReference<Map<String, String>> cacheData;

キャッシュ オブジェクトは、データベース テーブルから (遅延して) 読み込まれる必要があります。

キャッシュ データを呼び出し元に返すメソッドを提供しますが、データが null (つまり、読み込まれていない) の場合、コードはデータベースからデータを読み込む必要があります。同期を避けるために、compareAndSet() メソッドを使用することを考えました。

public Object getCacheData() {
  cacheData.compareAndSet(null, getDataFromDatabase()); // atomic reload only if data not set!
  return Collections.unmodifiableMap(cacheData.get());
}

このようにcompareAndSetを使用しても問題ありませんか。アトミックアクションの一部としてデータベース呼び出しを含めるには? メソッドを同期するよりも良い/悪いですか?

アドバイスをありがとう..

4

1 に答える 1

5

期待どおりの動作が得られません。この式:

cacheData.compareAndSet(null, getDataFromDatabase())

常に最初に呼び出しますgetDataFromDatabase()。つまり、データがキャッシュされたかどうかは問題ではありません。そうであれば、データベースを呼び出しますが、結果を破棄します。キャッシュは機能していますが、パフォーマンスも同様に貧弱です。

代わりにこれを考慮してください:

if(cacheData.get() == null) {
    cacheData.compareAndSet(null, unmodifiableMap(getDataFromDatabase()));
}
return cacheData.get());

完璧ではありませんが (getDataFromDatabase()最初は複数回呼び出すことができます)、後で期待どおりに動作します。またCollections.unmodifiableMap()、同じマップを何度もラップする必要がないように、以前に移動しました。

これにより、さらに簡単な実装が可能になります (不要synchronizedまたはAtomicReference必要):

private volatile Map<String, String> cacheData;

if(cacheData == null) {
  cacheData = unmodifiableMap(getDataFromDatabase());
}
return cacheData;
于 2012-10-20T20:45:10.193 に答える