2009-03-21 1 views
0

私は、インデックスを生成するプロデューサーアプリを持っています(それをいくつかのインメモリツリーデータ構造に保存しています)。また、コンシューマーアプリはこのインデックスを使用して部分一致を検索します。プロデューサー/コンシューマーアプリのデザイン

プロデューサがデータのインデックスを作成している間にコンシューマUIをブロックする必要はありません(一部のプログレスバーなど)。基本的に、ユーザが部分インデックスを使用したい場合は、そうするだけです。この場合、プロデューサは、ユーザーが別の画面に移動するまで、インデックス作成をしばらく停止する必要があります。

大雑把に言えば、これを達成するために待機/通知プロトコルが必要です。私の質問:それはビジネスをしている間、待機/通知を使用してプロデューサスレッドを中断することは可能ですか?これを達成するために必要なjava.util.concurrentプリミティブは何ですか?

答えて

0

プロデューサスレッドでは、何らかのメインループが発生する可能性があります。これはおそらくあなたのプロデューサーを中断させるのに最適な場所です。代わりに、待機()と私はあなたが潜在的にあなたは必ずその都度確認する必要があり、その

class Indexer { 

    Lock lock = new ReentrantLock();  

    public void index(){ 
     while(somecondition){ 
      this.lock.lock(); 
      try{ 
       // perform one indexing step 
      }finally{ 
       lock.unlock(); 
      } 
     } 
    } 

    public Item lookup(){ 
     this.lock.lock(); 
     try{ 
      // perform your lookup 
     }finally{ 
      lock.unlock(); 
     } 
    } 
} 

ような何かを行うことができ5.

あなたはJavaで導入されたJava同期オブジェクトを使用することをお勧め)(通知を使用しますインデクサーがロックを解除すると、インデックスは一貫した法的状態になります。このシナリオでは、インデクサーがロックを解除すると、新規または待機中のlookup()操作によってロックが取得され、ロックが完了して解放されます。その時点で、インデクサーは次の手順に進むことができます。lookup()が現在待機していない場合、インデクサはロック自体を再取得し、次の操作を続行します。

複数のスレッドが同時に検索を実行しようとしていると思われる場合は、ReadWriteLockインターフェイスとReentrantReadWriteLockの実装を調べることをお勧めします。

もちろん、このソリューションは簡単な方法です。ロックされていないスレッドのいずれかがブロックされます。あなたのデータ構造を直接同期することができるかどうかチェックしたいかもしれませんが、ビルド・インデックスはバランスのとれたツリーやB-Treeなどのノードを使用する傾向があるので、難しいかもしれません。

まず、簡単な方法を試してから、それがあなたに合った動作をするかどうかを確認することをお勧めします。そうでない場合は、索引付けステップを小さなステップに分割してみるか、データ構造の一部でのみ同期を試みてください。

ロックのパフォーマンスについてあまり気にしないでください。ロックされていないロック(ロックを取ろうとするスレッドが1つだけの場合)は安いです。あなたのロックの大部分が不一致である限り、ロックのパフォーマンスは心配するものではありません。

2

あなたがこれを記述したやり方では、あなたが待っている/通知する必要はありません。データ構造へのアクセスをシンクロして、アクセス時に一貫性のある状態になるようにします。

編集:「アクセスを同期させる」とは、データ構造全体を同期化すること(つまり、プロデューサまたはコンシューマをブロックすることになる)を意味するものではありません。代わりに、更新中のビットのみを同期させ、更新した時点でのみ同期化してください。プロデューサの作業のほとんどは非同期で実行できます。例えば、ツリーを構築する場合、挿入が必要なノードを特定し、そのノードで同期させ、挿入を行い、続けてください。

+0

データベースの行ロックに似た何かを提案しています。現在、ツリーは、1つのスレッドが通過できるようにロックされています。 –

0

プロデューサアプリケーションには、公開と作業中の2つのインデックスがあります。プロデューサは作業中のみで動作し、消費者は公開された状態でのみ動作します。プロデューサがインデックスを作成すると、作業中のものを公開されたもの(通常は1つのポインタを交換する)に置き換えることができます。プロデューサーは、価値がある場合に部分インデックスのコピーを公開することもできます。こうすることで、長期間のロックを避けることができます。消費者を失ってインデックスにアクセスすると便利です。

0

いいえ、それはできません。

スレッド自体に明示的なコードなしでスレッドに通知する唯一の方法は、スレッドで例外を発生させるThread.interrupt()を使用することです。 interrrupt()は通常、あまり信頼性が高くありません。なぜなら、コード内のいくつかのランダムなポイントで例外をスローすることは、すべてのコードパスで正しく動作するためです。それに加えて、スレッドのどこか(使用しているライブラリも含む)のtry {} catch(Throwable){}は、シグナルを飲み込むのに十分かもしれません。

ほとんどの場合、唯一正しい解決策は、コンシューマがプロデューサにメッセージを渡すために使用できる共有フラグまたはキューを使用することです。プロデューサが応答しない、またはフリーズすることを心配する場合は、別のスレッドで実行し、n秒ごとにハートビートメッセージを送信する必要があります。それがハートビートを送信しない場合は、それを殺す。 (プロデューサーが実際にフリーズしているのかどうかを判断し、外部イベントを待つだけでなく、正しいことを得るのは非常に難しいことが多いことに注意してください)。

+0

ここにいくつかの良いアイデアがありますが、いくつかの完全な誤りもあります。スレッドを中断することは、 "何らかのランダムな点で"例外を発生させません*。 InterruptedExceptionsがチェックされ、それをスローする可能性のあるメソッドが明確に定義されています。ひどく書かれた "catch-all"ブロックは、プログラムを破壊するのに十分です。 – erickson

+0

キューに関するあなたの提案はかなり面白いです。私ができることは、10個のツリー・ノードが処理されるごとに、消費者からの要求に対するプロデューサ・チェックを行うことです。私はちょうどこれがユーザーに反応するように見えるようにしています。 –