Guava Cache官网个人翻译

10069 ワード

LoadingCache graphs = CacheBuilder.newBuilder()
       .maximumSize(1000)
       .expireAfterWrite(10, TimeUnit.MINUTES)
       .removalListener(MY_LISTENER)
       .build(
           new CacheLoader() {
             public Graph load(Key key) throws AnyException {
               return createExpensiveGraph(key);
             }
           });

シーンの適用


キャッシュは多くのシーンで役立ちます.たとえば、計算に複数回アクセスする必要がある場合や、クエリーのロードにかかるコストが高い場合は、キャッシュの使用を検討できます.
GuavaのCache(後文でCacheと略記)はConcurrentMapに似ているが、全く同じではない.最も根本的な違いは、ConcurrentMapが表示されるまですべてのキャッシュ要素を保持することです.Cacheは、メモリの使用量を考慮して、キャッシュ要素の自動期限切れの構成ポリシーをサポートします.一部のシーンでは、GuavaのLoadingCache(後述するLoadingCache)がキャッシュを自動的にロードできるため、より便利です.
総じて、Guavaのキャッシュキットは、次のシーンで使用できます.
  • は、時間
  • を交換するために空間を使用することを望む.
  • 同じkey
  • に複数回アクセス
  • キャッシュが必要なデータは、使用可能なメモリ
  • を超えない.
    ヒント:
    Cacheの機能が不要な場合は、ConcurrentMapメモリの使用効率が向上します.しかし,ConcurrentMapを用いてCacheの特性を実現することは非常に困難であり,ほとんど不可能である.
     

    ≪ロード|Load|emdw≫


    Cacheを取得する方法はCacheBuilderによって構築され、カスタマイズされた構造Cacheをサポートします.
    Cacheを正式に取得する前に、キャッシュされたvalueがkeyでどのように得られたかを知る必要があります.以下にkey-valueをCacheにロードする方法を3つ示します.

    CacheLoaderから


    LoadingCacheは対応するCacheLoaderによって構築された.CacheLoaderを作成する最も典型的な方法は、V load(K key)throws Exceptionを実現するだけです.例えば以下のコード
    LoadingCache graphs = CacheBuilder.newBuilder()
           .maximumSize(1000)
           .build(
               new CacheLoader() {
                 public Graph load(Key key) throws AnyException {
                   return createExpensiveGraph(key);
                 }
               });

    LoadingCacheの古典的な使用はget(key)がキャッシュを取得することであり、keyに対応するvalueがキャッシュにすでに存在する場合は直接戻るメカニズムであり、そうでなければ前に定義したCacheLoaderを使用する.loadメソッドはvalueを取得し、返します.具体的な使用コードは以下の通りです.
    try {
      return graphs.get(key);
    } catch (ExecutionException e) {
      throw new OtherException(e.getCause());
    }

    tryCatchが必要な理由はCacheLoaderです.load()メソッドは、放出検査異常を宣言します.try-catchを使用したくない場合はgetUnchecked(key)メソッドを使用できますが、実際にloadが検査異常を投げ出すと、非検査異常に包装されて投げ出されます.具体的なコードは以下の通りです.
    LoadingCache graphs = CacheBuilder.newBuilder()
           .expireAfterAccess(10, TimeUnit.MINUTES)
           .build(
               new CacheLoader() {
                 public Graph load(Key key) { // no checked exception
                   return createExpensiveGraph(key);
                 }
               });

    キャッシュコードを取得するには、次の手順に従います.
    return graphs.getUnchecked(key);

    一括クエリーはgetAll(Iterable extends K>)メソッドで実現でき、getAllメソッドでキャッシュ内のすべての値を取得できます.一括クエリが単独クエリよりも効率的である場合、CacheLoaderを上書きすることによってloadAllメソッドを実装すると、対応するgetAll(Iterable)のパフォーマンスも向上します.
    loadAllメソッドを実装すると、不要なkey-valueが同じ時点でロードされることに注意してください.

    Callableから


    すべてのGuavaキャッシュはget(K,Callable)メソッドをサポートしている.このメソッドの意味は、対応するkey-valueがキャッシュされている場合、直接戻ることである.そうでなければCallableメソッドを実行してvalueを取得し、キャッシュして戻ります.
    Cache cache = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .build(); //  CacheLoader
    ...
    try {
      //  key value , doThingsTheHardWay(key) 
      cache.get(key, new Callable() {
        @Override
        public Value call() throws AnyException {
          return doThingsTheHardWay(key);
        }
      });
    } catch (ExecutionException e) {
      throw new OtherException(e.getCause());
    }

    直接挿入


    Cache.put(key,value)メソッドは、キャッシュ値を直接挿入することができ、このメソッドを実行すると、キャッシュに以前に存在していたkeyに対応するvalue値が上書きされます.Cacheを使用できます.asMap()ビューの公開された任意のConcurrentMapメソッドはキャッシュを修正するが、asMapビューの任意のメソッドはキャッシュアイテムが原子的にキャッシュにロードされることを保証することはできない.さらに、asMapビューの原子演算は、GuavaCacheの原子負荷の範疇外であるため、Cacheに比べる.asMap().putIfAbsent(K,V),Cache.get(K,Callable)は常に優先的に使うべきです.
     

    期限切れポリシー


    残念なことに、私たちはいつも必要なkey-valueをすべてキャッシュするのに十分なメモリを持っていません.いつkey-valueを持たないかを決めなければなりません.Guavaは、容量ベース、時間ベース、リファレンスベースの3つの基本的なキャッシュ期限切れポリシーを提供します.

    容量ベースの期限切れポリシー


    キャッシュが一定の容量を超えない場合はCacheBuilderを使用します.maximumSize(long)で設定します.キャッシュは、最近使用されていないkey-valueまたは頻繁に使用されていないkey-valueを回収しようとします.警告:キャッシュが最大容量に近づくと、リカバリが実行される可能性があります.
    また、キャッシュするvalueに異なる重み(メモリのサイズなど)がある場合は、CacheBuilderを使用します.Weigher(Weigher)はウェイトメソッドを指定し、CacheBuilder.を介してmaximumWeight(long)は、最大ウェイトを指定します.警告:同様に最大ウェイトに近づくと、回収操作が実行される可能性があります.また、ウェイトメソッドは作成または上書き時に計算され、このメソッドの複雑さを考慮する必要があります.
    LoadingCache graphs = CacheBuilder.newBuilder()
           .maximumWeight(100000)
           .weigher(new Weigher() {
              public int weigh(Key k, Graph g) {
                return g.vertices().size();
              }
            })
           .build(
               new CacheLoader() {
                 public Graph load(Key key) { // no checked exception
                   return createExpensiveGraph(key);
                 }
               });

    時間ベースの期限切れポリシー


    CacheBuilderは、2つの期限切れポリシーを提供します.
  • expireAfterAccess(long,TimeUnit)は、key-valueが最近アクセス(読み取りまたは書き込み)した後に期限切れになる.
  • expireAfterWrite(long,TimeUnit)は、key-valueが書き込みまたは再ロードされた後に期限切れになる.

  • ヒント:時間ベースの期限切れポリシーをテストするには、本当に時間が経つのを待つ必要はありません.CacheBuilderを使用するだけです.ticker(Ticker)法でテストをシミュレートできます.

    リファレンスベースの期限切れポリシー


    Guavaでは弱い参照設定keyとvalue、ソフト参照設定valueがサポートされています.
  • CacheBuilder.weakKeys()は弱参照でkeyを格納し,keyが強と軟参照を持たない場合keyはGCされる.
  • CacheBuilder.WeakValues()は弱い参照でvalueを格納し,valueに強い参照とソフト参照がない場合,valueはGCされる.
  • CacheBuilder.ソフトバリュー()はソフトリファレンスでvalueを格納し、valueに強いリファレンスがない場合、valueはメモリがオーバーフローする前にGCされる.

  • Guavaは、参照ベースの期限切れポリシーではなく、より予測的な容量ベースの期限切れポリシーを使用することを公式に推奨しています.

    アクティブフェイルオーバ


    いつでも、自動的に期限が切れるまで待つのではなく、key-valueをアクティブに無効にすることができます.
  • 単一失効、Cache.invalidate(key)
  • ロット失効、Cache.invalidateAll(keys)
  • はすべて失効しましたCacheinvalidateAll()

  • フェイルオーバーアクションのリスナー


    CacheBuilderを介して、キャッシュアイテムの無効化アクションのリスナーを定義できます.removalListener(RemovalListener)メソッドが実装されます.注意:リスナー内の異常は印刷され、飲み込まれます.
    CacheLoader loader = new CacheLoader () {
      public DatabaseConnection load(Key key) throws Exception {
        return openConnection(key);
      }
    };
    RemovalListener removalListener = new RemovalListener() {
      public void onRemoval(RemovalNotification removal) {
        DatabaseConnection conn = removal.getValue();
        conn.close(); // tear down properly
      }
    };
    
    return CacheBuilder.newBuilder()
      .expireAfterWrite(2, TimeUnit.MINUTES)
      .removalListener(removalListener)
      .build(loader);

    警告:デフォルトでは、Listenerメソッドは失効動作が発生したときに同期して呼び出されます.Listenerメソッドが非常に時間がかかると、一般的なキャッシュ機能に影響します.この場合は非同期で実現することができる、具体的にはRemovalListenersである.asynchronous(RemovalListener, Executor)

    クリーンアップはいつ発生しますか?


    CacheBuilderで構築されたCachesでは、valuesのクリーンアップと期限切れは自動的に実行されません.また、値が期限切れになった後にすぐに実行されるか、ソート操作は行われません.代わりに、書き込み操作時または書き込み操作が少ない場合には、読み出し操作で少量のメンテナンスが実行される.
    上記の理由は、キャッシュを継続的に維持するには、スレッドを作成して実装する必要があります.しかし,このスレッドの操作はユーザの操作と競合し,ロックを奪う可能性がある.また、一部の環境ではスレッドの作成が制限され、CacheBuilderが使用できない場合があります.
    したがって、私たちはこの権利をユーザーに与えます.キャッシュが高スループットである場合は、期限切れのキャッシュ・アイテムをクリーンアップする心配はありません.キャッシュの書き込みが非常に少ない場合は、キャッシュの読み取りをブロックする操作をクリーンアップしたくない場合は、Cacheをスケジュールするために別のスレッドを作成する必要があります.cleanUp()メソッド.
    メンテナンスキャッシュを定期的にクリーンアップしたい場合は、書き込み操作が非常に少ない場合は、ScheduledExecutorServiceを使用します.

    更新


    リフレッシュと有効期限が異なります.更新はLoadingCacheを通ります.refresh(K)が実現され、リフレッシュ動作は非同期である可能性がある.keyがリフレッシュを開始すると、古い値は依然としてアクセスできます.逆に、valueが期限切れになると、新しい値がロードされるまで強制的に待機します.
    リフレッシュ時に異常が発生すると、古い値が保存され、異常が印刷され、飲み込まれます.
    CacheLoaderはCacheLoaderを上書きできます.reloadメソッドでは、リフレッシュ時にスマートな動作を使用し、新しい値を計算するときに古い値を使用することを指定します.
    //  key ,  .
    LoadingCache graphs = CacheBuilder.newBuilder()
           .maximumSize(1000)
           .refreshAfterWrite(1, TimeUnit.MINUTES)
           .build(
               new CacheLoader() {
                 public Graph load(Key key) { // no checked exception
                   return getGraphFromDatabase(key);
                 }
    
                 public ListenableFuture reload(final Key key, Graph prevGraph) {
                   if (neverNeedsRefresh(key)) {
                     return Futures.immediateFuture(prevGraph);
                   } else {
                     // asynchronous!
                     ListenableFutureTask task = ListenableFutureTask.create(new Callable() {
                       public Graph call() {
                         return getGraphFromDatabase(key);
                       }
                     });
                     executor.execute(task);
                     return task;
                   }
                 }
               });

    自動タイミングリフレッシュはCacheBuilder.refreshAfterWrite(long,TimeUnit)追加.expireAfterWriteと比較して、refreshAfterWriteは一定時間後にリフレッシュされますが、リフレッシュ動作はキャッシュ・アイテムがアクセスされたときに発生します.CacheLoader.reloadは非同期で実装され、クエリはリフレッシュ動作によって遅延されません.refreshAfterWriteとexpireAfterWriteを同時に使用できます.

     


    とくせい


    ≪ステータス|Status|emdw≫


    CacheBuilderを呼び出す.recordStats()は、キャッシュされた状態の集合を得ることができます.Cache.stats()メソッドは、次のような状態情報を提供するCacheStatsオブジェクトを返します.
  • hitRate()、命中率
  • averageLoadPenalty()は、新しい値をロードする平均消費時間、単位ナノ秒
  • evictionCount()、期限切れキャッシュ数
  • 他にもステータスメソッドがあります.パフォーマンスの重要なアプリケーションでは、これらのステータスを表示することをお勧めします.

    asMap


    asmapビューを使用してconcurrentmapとしてキャッシュを表示できますが、asmapビューがキャッシュとどのように対話するかについては説明が必要です.
  • cache.asMap()は現在ロードされているすべてのキャッシュアイテムを含むのでcache.asMap().keySet()には、現在ロードされているすべてのkeyが含まれます.
  • asMap().get(key)とcache.getIfPresent(key)は同じ役割を果たし、値のロードは発生しません.
  • アクセス時間は、キャッシュの読み取りおよび書き込み操作時にリセットされます.Cacheも含めてasMap().get(Object)とCache.asMap().put(key,value)だがcontainsKey(Object)とCacheは含まれない.asMap()操作.だから、cache.asMap().EntrySet()のループもアクセス時間をリセットしません.

  •  


    わりこみ


    Loadingメソッド(getメソッドのような)は割り込み異常を放出しません.この方法は割り込みをサポートするように設計できますが、私たちは持っていません.サポート中断は少数のユーザーのみが利益を得るため、多くのユーザーはかえって使用コストを増加させます.詳しい理由は、英語の原文を読むことができます.