21

volatile HashMap<T>キャッシュアイテムを格納するためのを含むキャッシュクラスがあります。

volatile HashMapに変更した場合の結果はどうなるのでしょうConcurrentHashMapか。

パフォーマンスが向上しますか?このキャッシュは読み取り専用キャッシュです。

使用するのに最適なオプションは何ですか?HashMapだけですか?キャッシュは一定の間隔で投入されています。

4

4 に答える 4

46

volatileまず、キーワードの機能がわからないようです。宣言された変数によって保持されている参照値volatileが変更された場合、他のスレッドはキャッシュされたコピーを持つのではなく、それを参照するようになります。アクセスに関しては、スレッドセーフとは何の関係もありません。HashMap

それと、読み取り専用であると言うという事実を考えると、HashMapスレッドセーフを提供するものを使用する必要はありません。ConcurrentHashMap

編集して追加:最後の編集で「キャッシュは一定の間隔で読み込まれています」と表示されます

それは読み取り専用ではありませんね。

書き込み中(既存のHashMapを更新)にスレッドから読み取りを行う場合はConcurrentHashMap、はいを使用する必要があります。

まったく新しいHashMapものを入力し、それを既存の変数に割り当てる場合は、次を使用します。volatile

于 2012-04-27T21:09:52.843 に答える
6

キャッシュは読み取り専用であると言いますが、矛盾しているように見える間隔で更新されます。

キャッシュ全体が一定の間隔で更新される場合は、volatileを使い続けます。volatileは、更新されたマップが安全に公開されていることを確認します。

public final class  Cache
{
   private volatile Map<?,?> cache;

   private void mapUpdate() {
      Map<?,?> newCache = new HashMap<>();

      // populate the map

      // update the reference with an immutable collection
      cache = Collections.unmodifiableMap(newCache);
   }
}

間隔の更新で同じキャッシュが変更される場合は、ConcurrentHashMapを使用するか、マップをコピーしてコピーを更新し、参照を更新することをお勧めします。

public final class  Cache
{
   private volatile Map<?,?> cache;

   private void mapUpdate() {
      Map<?,?> newCache = new HashMap<>(cache);

      // update the map

      // update the reference with an immutable collection
      cache = Collections.unmodifiableMap(newCache);
   }
}
于 2012-04-27T21:22:22.690 に答える
0

Webアプリケーションにも同様のユースケースがあります。インメモリキャッシュにHAshMapを使用しています。ユースケースは次のとおりです-

  1. 1つのユーザー要求が着信し、最初に入力キーを使用してレコードの存在についてキャッシュをチェックします。これは、addメソッドで実行されます。
  2. オブジェクトが存在しない場合は、新しいレコードがキャッシュに挿入されます。
  3. 同様に、removeメソッドでは、最初にキーを使用してキャッシュ内のレコードの存在を確認し、見つかった場合はそれを削除します。

2つのスレッドが1つを追加時に、もう1つを削除時に同時に実行していることを確認したいのですが、このアプローチでは、それらの時点でキャッシュ内の最新のデータを確認できますか?私が間違っていない場合は、同期メソッドがスレッドセーフを処理し、volatileが可視性を処理します。

private volatile HashMap<String,String> activeRequests = new HashMap<String,String>();
public synchronized boolean add(String pageKey, String space, String pageName) {
    if (!(activeRequests.get(pageKey) == null)) {
       return false;
    }
    activeRequests.put(pageKey, space + ":" + pageName);
    return true;
}

public synchronized void remove(String pageKey) {       
    if(!(activeRequests.get(pageKey) == null))
        activeRequests.remove(pageKey);
    }
于 2019-08-09T04:35:53.583 に答える
0

AFAIKは、最初の答えが正しく説明していますが、ユースケースによっては、頻繁に更新および置換されるキャッシュでvolatileを使用することは不要なオーバーヘッドであり、これが単なる静的メタデータスナップショットであり、他のスレッドによって更新されないと仮定すると、実際には悪いまたは一貫性がない可能性があります。

キャッシュからすべてを読み取って必要なすべてを取得するHttpリクエストの例をとると、リクエストはマップの参照を使用し、参照からいくつかのキーの読み取りを開始し、読み取りの途中でキャッシュ参照が更新されます。新しいハッシュマップ(更新)。キャッシュの異なる状態の読み取りを開始し、キャッシュ内のエントリが特定の時間のスナップショットTのものでない場合、一貫性がなくなる可能性があります。volatileでは、T1でKey1:Val1を読み取り、T2でKey2:Val2を読み取りますが、T1で同じスナップショットに対してVal1、Val2を読み取る必要があります。volatileを使用すると、参照は常に更新され、Key1:Val1を最初に読み取り、Key1:Val2を2回読み取り、同じリクエストで異なるデータを提供できます。

volatileがない場合、リクエストは、処理が完了するまで常に参照スナップショットを指す参照を使用します。volatileがない場合、常にT1でKey1:Val1を読み取り、 T2で同じ値Key2:Val1を読み取ります。この参照を使用するすべてのリクエストが完了すると、古い参照解除されたマップがGCされます。

于 2021-06-18T20:21:33.887 に答える