1

最近、LoadingCacheクラスを使い始めましたが、予期しない動作が発生しています。私は今解決策を知っていますが、他の人がそれから学ぶことができるように質問を投稿しています。

基本的に、特定のキーのキャッシュにnull以外の値を入れます。キーはファイル内の値の位置であり、CacheLoader.load()メソッドを使用して、ファイルから値を読み取ることができます。現在、LoadingCacheは単一のスレッドによって使用されています。

アプリケーションを実行すると、以前にnull以外の値を挿入するために使用されたキーのnull値を使用して削除通知リスナーが呼び出されます。キャッシュに入るすべての値がnullでないことを確認するためにassertステートメントを使用したので、これを知っています(これはとにかく起こらないはずです)。また、CacheLoader.load()によって呼び出されるメソッドでキーを出力したため、これを確認できます。CacheLoader.load()は、キーを出力するメソッドを呼び出すことができる唯一のメソッドです。さらに、このメソッドはnull値を返すことはできません。

私が何か間違ったことをしているのか誰かが私に知らせてくれたら、私は大いに義務づけられるでしょう。

以下は、ロードキャッシュの私の定義です。

    private LoadingCache<Long,T> gcache( ) {
        @SuppressWarnings( Constants.UNCHECKED )
        final CacheLoader<Long,T> loader =
            new CacheLoader<Long,T>() {
                public T load(Long key) {
                    // This following method _did_ print the key for which
                    // the RemovalNotification listener returns a null value.
                    // See output further on.
                    return getElement( key );
                }
            };
        @SuppressWarnings( Constants.UNCHECKED )
        final RemovalListener<Long,T> listener
            = new RemovalListener<Long,T>( ) {
                  @Override
                  public void onRemoval( RemovalNotification<Long,T> notification ) {
                      final T value = notification.getValue( );
////////////////////////////////////////////////////////////////////////////
if (value == null) {
System.out.println( "????: " + notification.getKey( ) );
}
assert( value != null);
////////////////////////////////////////////////////////////////////////////
                      if (!value.immutable( )) {
                          put( notification.getKey( ), value );
                      }
                  }
              };
        @SuppressWarnings( Constants.UNCHECKED )
        final LoadingCache<Long, T> gcache
            = CacheBuilder.newBuilder( )
                          .softValues( )
                          .removalListener( listener )
                          .build( loader );
        return gcache;
    }

    private T getElement( long pos ) {
        // Critical section, but at the moment there's only one thread.
        enter( );
        seek( pos );
        final T creation = inflator.inflate( this );
///////////////////////////////////////////////////////////////////////
System.out.println( "getElement: pos = " + pos );
assert( creation != null );
///////////////////////////////////////////////////////////////////////
        leave( );
        return creation;
    }

出力の一部:

[ cut ]
getElement: pos = 362848
[ cut ]
????: 362848

疑問符の後に、制御できない量の出力が表示され、JVMを停止するのが困難です。アプリケーションを終了する前に、キーを数回押す必要があります。(もちろん、killでもうまくいきますが、キーボードの方が少し高速です。)

4

1 に答える 1

6

私はただ推測しています:javadocでRemovalNotificationそれは読みます

単一のエントリの削除の通知。キーや値がすでにガベージコレクションされている場合は、nullになる可能性があります。

を使用していますsoftValues()。値がGCされると、エントリ全体がキャッシュから削除され、キーも収集される可能性があります。

于 2012-08-26T18:12:07.290 に答える