JavaRush /Java Blog /Random-JA /Java での SynchronousQueue の例 - 問題の解決Producer Consumer
profeg
レベル 18

Java での SynchronousQueue の例 - 問題の解決Producer Consumer

Random-JA グループに公開済み
Java での SynchronousQueue の例 - 問題の解決Producer Consumer
SynchronousQueue は特別なタイプの BlockingQueue であり、各挿入操作は別のスレッドの対応する削除コマンドを待機する必要があり、その逆も同様です。SynchronousQueue でput() メソッドを呼び出すと、別のスレッドがその要素を取得するまでブロックされます。したがって、別のスレッドがそこから要素を削除しようとしたときに、その要素が存在しない場合、そのスレッドは、他のスレッドが要素をキューに入れるまでブロックされます。SynchronousQueue をオリンピックの聖火を持って走るアスリート (スレッド) と考えることができます。彼は聖火 (受け継がれるオブジェクト) を持って走り、反対側で待っている別のアスリートに聖火を渡します。名前に注目すると、SynchronousQueue が別のスレッドにデータを同期的に転送するという理由でそのように名付けられていることがわかります。データを挿入して終了するだけ (非同期操作) ではなく、誰かがデータを取得するのを待ちます。CSP と Ada に精通している場合は、同期キューがスレッドの会議に似ていることがわかります。これらは、あるスレッドで実行されているオブジェクトが別のスレッドのオブジェクトと何らかの情報、イベント、またはタスクを渡すために同期する必要がある制御転送構造に適しています。これまでのマルチスレッド プログラミング チュートリアルでは、wait メソッド、notify メソッド、およびBlockingQueueメソッドを使用して、プロデューサーとコンシューマーの問題を解決する方法を学びました。次に、 SynchronousQueue を使用してプロデューサー/コンシューマー パターンを適用する方法を学びます。このクラスはさらに、プロデューサー スレッドとコンシューマー スレッドの待機を順序付けるための公平な動作をサポートします。デフォルトでは、この順序は保証されません。ただし、公平なプロパティで作成されたキューは、FIFO (先入れ先出し) キュー内のスレッドへのアクセスを保証します。
Java で SynchronousQueue を使用するプロデューサー/コンシューマー。
Java での SynchronousQueue の例 - 問題の解決Producer Consumer - 1上で述べたように、プログラミング言語におけるスレッド間通信を理解する には、プロデューサーとコンシューマーの問題ほど優れたものはありません。この問題では、1 つのスレッドがイベントとタスクを生成するプロデューサーとして機能し、もう 1 つのスレッドがそのコンシューマーとして機能します。共有バッファは、プロデューサーからコンシューマーにデータを転送するために使用されます。この問題を解決することは極端な場合に困難になります。たとえば、製造業者が次のような理由で待機せざるを得なくなった場合です。バッファがいっぱいであるか、コンシューマは待機を余儀なくされています。バッファが空です。これは簡単に解決できたので... ブロッキング キューは、データを保存するためのバッファーだけでなくフロー制御も提供し、バッファーがいっぱいの場合は put() メソッド (プロデューサー) を呼び出すスレッドをブロックし、バッファーがいっぱいの場合は take() メソッド (コンシューマー) を呼び出すスレッドをブロックします。バッファが空でした。次に、容量ゼロの特別な種類の並列コレクションである SynchronousQueue を使用して、これと同じ問題を解決します。次の例では、 PRODUCERCONSUMERという2 つのスレッドがあります(常にスレッドに名前を付けます。これはマルチスレッド プログラミングの非常に良いスタイルです)。最初のスレッドはゲーム内のスコアを投稿し、2 番目のスレッドはそれを消費します。ゲームのスコアは String 型のオブジェクトにすぎません。ただし、別のタイプでプログラムを実行すると、違いはわかりません。SynchronousQueue の仕組みと、プロデューサーとコンシューマーの問題の解決方法を理解するには、Eclipse 環境でデバッグ (デバッグ) 用のプログラムを実行するか、単に Consumer.start() をコメントアウトしてプロデューサー スレッドを開始する必要があります。コンシューマ スレッドが実行されていない場合、プロデューサ スレッドは queue.put(event) でブロックされます。実行している場合、:FOUR イベントを発行しているプロデューサー [PRODUCER] は表示されません。これが起こる理由は、SynchronousQueue の特定の動作。これにより、データを投稿するスレッドは別のスレッドがデータを取得するまでブロックされ、その逆も同様です。残りのコードは、Producer.start(); をコメントアウトすることでテストできます。そしてコンシューマスレッドのみを開始します。 プログラムが出力する内容を注意深く観察すると、出力の順序が逆になっていることがわかります。[PRODUCER]スレッドがデータを生成する前に、 [CONSUMER]スレッドが データを取得したようです。これは、SynchronousQueue がデフォルトではキューイングを保証しないためです。ただし、スレッドへのアクセスを FIFO 順に設定する公平性ルールがあります。これらのルールを有効にするには、次のように オーバーロードされたSynchronousQueue コンストラクターに true を渡します。 import java.util.concurrent.SynchronousQueue; /** * Java Program to solve Producer Consumer problem using SynchronousQueue. A * call to put() will block until there is a corresponding thread to take() that * element. * * @author Javin Paul */ public class SynchronousQueueDemo{ public static void main(String args[]) { final SynchronousQueue queue = new SynchronousQueue (); Thread producer = new Thread("PRODUCER") { public void run() { String event = "FOUR"; try { queue.put(event); // thread will block here System.out.printf("[%s] published event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; producer.start(); // starting publisher thread Thread consumer = new Thread("CONSUMER") { public void run() { try { String event = queue.take(); // thread will block here System.out.printf("[%s] consumed event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; consumer.start(); // starting consumer thread } } Output: [CONSUMER] consumed event : FOUR [PRODUCER] published event : FOUR new SynchronousQueue(boolean fair).
Java の SynchronousQueue について覚えておくべきこと。

Java におけるこの特殊なタイプのブロッキング キューの重要なプロパティをいくつか紹介します。あるスレッドから別のスレッドに同期してデータを渡すことは非常に便利です。このキューには容量がないため、別のスレッドがキューを解放するまでブロックされます。

  1. SynchronousQueue はブロックし、1 つのスレッドがデータを受け取る準備ができるまで、別のスレッドがデータを書き込もうとします。
  2. SynchronousQueue にはスコープがありません。つまり、データは含まれていません。
  3. SynchronousQueue は、前方キューイング戦略を実装するために使用されます。この戦略では、スレッドが待機中のスレッドに制御を渡すか、許可されている場合は新しいスレッドを作成します。許可されていない場合は、制御は転送されません。
  4. このキューでは null データは許可されません。null 要素を追加しようとすると、NullPointerException がスローされます。
  5. Collection の他のメソッド (contains など) を使用する場合、SynchronousQueue は空のコレクションのように動作します。
  6. 要素は削除しようとしたときにのみ存在するため、SynchronousQueue の Peak メソッドは使用できません。また、別のスレッドが要素の削除を試行するまでは、(どのようなメソッドを使用しても) 要素を挿入することはできません。
  7. SynchronousQueue にイテレータを使用することはできません。理由は次のとおりです。要素がありません。
  8. SynchronousQueue は公平なルールで作成でき、スレッドへのアクセスは FIFO 順序で保証されます。
おそらく、これはすべて Java の SynchronousQueue に関するものですこのマルチスレッド コレクションの特別な機能のいくつかを確認し、Java で SynchronousQueue を使用して古典的なプロデューサーとコンシューマーの問題を解決する方法を学びました。ちなみに、これを Queue と呼ぶのは完全に正しいわけではありません。要素は含まれていません。put() の呼び出しは、別のスレッドが take() を呼び出すまで完了しません。スレッドがオブジェクトを共有する、スレッドの集合場所と考えるのがより正確です。言い換えれば、これは Java でオブジェクトを同期して渡すためのユーティリティであり、おそらくwait and Noticeメソッドのより安全な代替手段となります。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION