0

大量のデータが(バックグラウンドスレッドによって)事前に読み込まれ、いっぱいになるまで使用できないキャッシュがあります(また、頻繁に再読み込みされ、その読み込み中は使用できなくなります)。isLoaded()これを使用するクラスがアクセス前にフラグをチェックするようにしたい。私は次のようなアクセス制御のためにReentrantReadWriteLockを使用します(簡単にするためにコードではこれを省略しています)。

public class Cache {

   private volatile boolean loaded = false; //starts false

   private static String[] cache;

   private static Lock readLock;
   private static Lock writeLock;

   public Object get(Object key) {
       if (!readLock.tryLock()) throw IllegalStateException(...);
       try {
           ... do some work
       } finally {
           readLock.unlock();
       }
   }

   // called by background thread
   private void loadFull() {
      loaded = false;
      writeLock.lock()
      try {
          cache = new String[];
          ... fill cache
      } finally {
          writeLock.unlock();
          loaded = true;
      }
   }
....
}  

今、私の他のクラスには、次のようなブロックがあります。

if (cache.isLoaded()) {
    try {
      Object x = cache.get(y);
    } catch (IllegalStateException iex) {
      // goto database for object
    }
} else {
    // goto database for object
}

本当に必要try/catchですか?フラグがfalseに設定され、readLock try()が失敗する可能性はありますか?フラグを気にせず、例外をキャッチする必要があります(例外がスローされた場合、フラグがfalseであるかのように基本的に同じコードを実行するため)。ちょっとおかしなことをしているような気がしますが、指が上がれません。ありがとう。

4

3 に答える 3

2

本当にtry/catchが必要ですか?フラグがfalseに設定され、readLock try()が失敗する可能性はありますか?

はい、必要です。cache.isLoaded()とが呼び出されるまでの間cache.get()に、ライターが入って書き込みロックを取得できます。この場合、cache.isLoaded()は戻りますtruecache.get()、例外がスローされます。

フラグを気にせず、例外をキャッチする必要があります(例外がスローされた場合、フラグがfalseであるかのように基本的に同じコードを実行するため)。

示したコードから、例外はget読み取りロックの取得に失敗した場合にのみスローされます。読み取りロックの取得は、その時点で同時書き込みが存在する場合にのみ失敗します。isLoadedまた、まさにこのシナリオではfalseを返します。したがって、例外に依存するだけで十分です。また、特殊なを作成することを検討してCacheStaleExceptionください。

于 2010-12-07T19:16:39.640 に答える
1

tryLock他のスレッドがすでにそのロックを取得している場合、は失敗します。これは通常、競合が多い(複数のクライアントが同じキャッシュにアクセスしている)ためにクライアントがロックの取得に失敗した場合に例外がスローされることを意味します。そのような状況に対処するためにクライアントレイヤーに実装したフォールバック戦略はありますか?

また、なぜstaticロックするのですか?キャッシュは通常、アプリケーションでシングルトンとして使用されますが、ロックを静的にすることでその使いやすさを制限する必要はないと思います。

于 2010-12-07T18:44:17.297 に答える
0

いいえ、しかし正直に言うと、あなたのパラダイムは混乱を招きます。おそらく、実際のデータベースに移動するにはコストがかかり、それがキャッシュの目的です。キャッシュがリロードされている場合、それがリロードされるまで待つ方が良いのではないでしょうか。

読み取りロックがすぐに利用できない場合に本当にデータベースにアクセスしたいと仮定すると、次のようになります。

   public Object get(Object key) {
       Object returnValue;
       if (readLock.tryLock()) {
           try {
               ... do some work
               returnValue = ...
           } finally {
               readLock.unlock();
           }
       } else {
           //go to database
           returnValue = ...
       }
       return returnValue;
   }
于 2010-12-07T19:01:32.863 に答える