2017-12-07 6 views
0

サーバがクライアントからメッセージを受信するたびに、メッセージはキューに入れられます。複数のスレッドがキューにデータを入力できますが、一度に1つのスレッドだけがそれから読み込み/処理する必要があります。キューにメッセージがある限り、処理スレッドは生きているはずです。どのように私はこの作品を作るのですか?メッセージキューが空でない場合は常に処理スレッドを実行します。

処理ロジックを同期メソッドに入れ、すべてのリクエストに対してこのメ​​ソッドを呼び出す新しいスレッドを開始すると、メモリ内のすべてのスレッドを持つリソースが浪費されることはありませんか?一方

、私はそれぞれの要求は、それが実行されていない場合は、それを起動しようとすると、単一の処理スレッドを使用する場合:

public void onMessage(String message) { 
    addToQueue(message); 
    synchronized (lock) { 
     if (!processingThread.isAlive()) 
      processingThread.start(); 
    } 
} 

// processing thread 
public void process() { 
    while (true) { 
     String message = queue.poll(); 
     synchronized (lock) { 
      if (message == null) 
       return; 
     } 
     // process message 
    } 
} 

どのように私はこのシナリオに実行していないことを確認することができます:

  1. 処理スレッドは、次の要素のキューをポーリングします。共有ロックを取得し、同期ブロックに入ります。それは、キューから読み取られた要素がnullであることをチェックして調べるので、キューは空です。 スレッドはロックを解除しますが、そのフラグはまだfalseに設定されていません。
  2. クライアント要求が到着し、キューにメッセージが追加されます。受信メソッドはロックを取得し、同期ブロックに入ります。処理スレッドはまだ生きているので、開始する必要はありません。このメソッドはロックを解除します。
  3. 処理スレッドがロックを解除して終了しました。

この場合、未処理のメッセージがキューに1つあります。このシナリオは起こりますか?大胆な文章が示唆するように、スレッドが死ぬ前にロックを解除することはできますか?

答えて

0

これは消費者/生産者の問題です。処理スレッド(コンシューマ)を停止/開始する必要はありません。ブロックすることができ、キュー内のメッセージを待機します。クライアントスレッド(プロデューサ)がキューを満たし、notify()の消費者スレッドがブロックを解除し、メッセージを削除して再び待機します。例はhttps://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.htmlです。

+0

しかし、 'put'メソッドは同期化されていますので、複数のプロデューサを使用したい場合は、順番を待つ必要があり、並行キューの利点が失われます。別の方法がありますか? – devil0150

+0

putは、2つのプロデューサが同時にキューに追加されないように同期する必要がありますが、プロデューサはキューが満杯になったときだけ待機する必要があります。キューが満杯でない場合、プロデューサはメッセージを追加し、notifyAllを呼び出して待機せずに終了します。 –

+0

しかし、2人のプロデューサが同時にキューに追加できるようにしたいと思っています。この場合、2人の異なるプロデューサが同時に「put」を呼び出そうとすると、キューの1つが満杯でなくても、もう1人が返すのを待たなければなりません。 – devil0150

関連する問題