Javaでスレッド間の通信を実装するためにwaitとnotifyを使用する方法
1. スレッド通信が必要な理由
スレッドは同時に実行され、これはスレッドのランダムな実行のように見えますが、実際のアプリケーションではスレッドを使用します。通信 実行順序が必要なので、スレッド通信を使用する必要があります。
スレッド通信 スレッドの実行順序を解決するために優先順位を使用してみてはいかがでしょうか?
全体の優先度は、スレッド PCB 内の優先度情報とスレッドの待機時間によって決定されるため、一般的な開発では、スレッドの実行順序を示すために優先度に依存することはありません。
参照以下のようなシーン: 生産者と消費者モデルを説明するためのパン屋の例
生産者と消費者に対応する、パン屋と顧客がいるパン屋があります。パン屋にはパンを保管するための在庫があります。在庫がいっぱいになると、生産されなくなります。同時に、消費者はパンも購入します。パンの在庫が売り切れると、消費者は引き続き購入する前に、新しいパンが生産されるまで待たなければなりません
分析: いつ生産を停止し、いつ消費を停止するかについて、生産と消費の情報を正確に伝えるためにスレッド通信を適用する必要があります
2. 待機メソッドと通知メソッド
wait() : 現在のスレッドによって保持されているオブジェクトを許可します。 ロックを解放して待機します。
wait(long timeout): 対応するパラメータは、スレッドが待機する時間です。
notify(): スレッドを起動します。同じオブジェクトを使用して wait を呼び出し、待機中のスレッドに入り、再度オブジェクト ロックを競合します。
notifyAll(): 複数のスレッドが待機している場合、notifyAll はすべてのスレッドを起動し、notify はランダムに 1 つを起動します
注:
これらのメソッドはすべて、オブジェクト クラスのメソッドに属します。
同期された同期コード ブロック/同期メソッドで使用する必要があります
どのオブジェクトがロックされているかは、wait と notify に使用されるオブジェクトです。
notify 直後に起動せず、同期が完了するまで待ってから起動します。
1 .wait() メソッド
wait メソッドの呼び出し後:
現在のコードを実行しているスレッドを待機させます (スレッドは待機キューに入れられます)
現在のロックを解放します
特定の条件が満たされると起動し、再度ロックの取得を試みます
待機終了の条件:
他のスレッドがオブジェクトのnotifyメソッドを呼び出す
wait待機時間タイムアウト(待ち時間を指定するタイムアウトパラメータ)
他のスレッドが割り込みメソッドを呼び出すとwaitがInterruptedExceptionをスローする
2. Notice() メソッド
##パラメータなしで wait メソッドを使用する場合は、notify メソッドを使用してスレッドをウェイクアップして待機する必要がありますこのメソッドはウェイクアップするためのものですオブジェクトのオブジェクト ロックを待機しているスレッドを起動して、オブジェクトのオブジェクト ロックを再取得できるようにします。 待機中のスレッドが複数ある場合、スレッド スケジューラは待機ステータス スレッドをランダムに選択します (最初のスレッドはありません)。 -come, first-served)notify() メソッドの後、現在のスレッドはオブジェクト ロックをすぐに解放せず、notify() メソッドを実行しているスレッドがプログラムの実行を終了するまで待機します。 、同期コードを終了します オブジェクトのロックは、ブロックの後でのみ解放されます3.notifyAll() メソッドこのメソッドは、起動時を除き、notify() メソッドと同じ効果があります。起動すると、待機中のすべてのスレッドが起動されますnotify() メソッドはランダムにスレッドを起動するだけです 3. wait と Notice を使用してベーカリー ビジネスを実装します
前提条件:
はい 2 人のパン屋がいます。パン屋は一度に 2 つのパンを作ることができます。倉庫には 100 のパンを保管できます。消費者は 10 人いて、各消費者は 1 つずつ購入します注:
消費と生産は同時に並行して実行され、1 つの生産と 1 つの消費ではありません。 #実装コード:public class Bakery { private static int total;//库存 public static void main(String[] args) { Producer producer = new Producer(); for(int i = 0;i < 2;i++){ new Thread(producer,"面包师傅-"+(i-1)).start(); } Consumer consumer = new Consumer(); for(int i = 0;i < 10;i++){ new Thread(consumer,"消费者-"+(i-1)).start(); } } private static class Producer implements Runnable{ private int num = 3; //生产者每次生产三个面包 @Override public void run() { try { while(true){ //一直生产 synchronized (Bakery.class){ while((total+num)>100){ //仓库满了,生产者等待 Bakery.class.wait(); } //等待解除 total += num; System.out.println(Thread.currentThread().getName()+"生产面包,库存:"+total); Thread.sleep(500); Bakery.class.notifyAll(); //唤醒生产 } Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } } } private static class Consumer implements Runnable{ private int num = 1; //消费者每次消费1个面包 @Override public void run() { try { while(true){ //一直消费 synchronized (Bakery.class){ while((total-num)<0){ //仓库空了,消费者等待 Bakery.class.wait(); } //解除消费者等待 total -= num; System.out.println(Thread.currentThread().getName()+"消费面包,库存:"+total); Thread.sleep(500); Bakery.class.notifyAll(); //唤醒消费 } Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } } } }
部分的な印刷結果:
4. ブロッキング キューブロッキング キューは特殊なキューです。これも「先入れ先出し」の原則に従っており、スレッドセーフなキュー構造です。
特徴: 典型的な生産者/消費者モデルで、一般にタスクの分離とピーク削減に使用されます
キューがいっぱいの場合、キューはブロックされて待機します (実稼働)、他のスレッドがキューから要素を取得するまで
キューが空の場合、キューはブロックされて待機します (消費)、他のスレッドが要素を挿入するまで待機します1. プロデューサー コンシューマー モデル
プロデューサー/コンシューマー モデルは、コンテナーを使用して、プロデューサーとコンシューマー間の強い結合の問題を解決します。
プロデューサーとコンシューマーは、次のことを行います。相互に直接通信するのではなく、ブロッキングを介して通信します キューは通信に使用されるため、プロデューサーがデータを生成した後、コンシューマーがデータを処理するのを待って、それをブロッキング キューに直接スローします。コンシューマーはプロデューサーに要求しません。
ブロッキング キューは、バッファ内でプロデューサーとコンシューマの処理能力のバランスをとります。
ブロッキング キューは、プロデューサーとコンシューマを分離することもできます上記のベーカリー ビジネスの実装は生産者消費者モデルです。 例
2. 標準ライブラリのブロッキング キュー
ブロッキング キューは Java 標準ライブラリに組み込まれています。一部のプログラムではブロッキング キューを使用する必要がありますが、標準ライブラリではブロッキング キューを直接使用する必要があります。
BlockingQueue 是一个接口. 真正实现的类是 LinkedBlockingQueue
put 方法用于阻塞式的入队列, take 用于阻塞式的出队列
BlockingQueue 也有 offer, poll, peek 等方法, 但是这些方法不带有阻塞特性
BlockingDeque<String> queue = new LinkedBlockingDeque<>(); queue.put("hello"); //如果队列为空,直接出出队列就会阻塞 String ret = queue.take(); System.out.println(ret);
3. 阻塞队列的模拟实现
这里使用数组实现一个循环队列来模拟阻塞队列
当队列为空的时候,就不能取元素了,就进入wait等待,当有元素存放时,唤醒
当队列为满的时候,就不能存元素了,就进入wait等待,当铀元素取出时,唤醒
实现代码:
public class MyBlockingQueue { //使用数组实现一个循环队列,队列里面存放的是线程要执行的任务 private Runnable[] tasks; //队列中任务的数量,根据数量来判断是否可以存取 private int count; private int putIndex; //存放任务位置 private int takeIndex; //取出任务位置 //有参的构造方法,表示队列容量 public MyBlockingQueue(int size){ tasks = new Runnable[size]; } //存任务 public void put(Runnable task){ try { synchronized (MyBlockingQueue.class){ //如果队列容量满了,则存任务等待 while(count == tasks.length){ MyBlockingQueue.class.wait(); } tasks[putIndex] = task; //将任务放入数组 putIndex = (putIndex+1) % tasks.length; //更新存任务位置 count++; //更新存放数量 MyBlockingQueue.class.notifyAll(); //唤醒存任务 } } catch (InterruptedException e) { e.printStackTrace(); } } //取任务 public Runnable take(){ try { synchronized (MyBlockingQueue.class){ //如果队列任务为空,则取任务等待 while(count==0){ MyBlockingQueue.class.wait(); } //取任务 Runnable task = tasks[takeIndex]; takeIndex = (takeIndex+1) % tasks.length; //更新取任务位置 count--; //更新存放数量 MyBlockingQueue.class.notifyAll(); //唤醒取任务 return task; } } catch (InterruptedException e) { throw new RuntimeException("存放任务出错",e); } } }
五. wait和sleep的区别(面试题)
相同点:
都可以让线程放弃执行一段时间
不同点:
☘️wait用于线程通信,让线程在等待队列中等待
☘️sleep让线程阻塞一段时间,阻塞在阻塞队列中
☘️wait需要搭配synchronized使用,sleep不用搭配
☘️wait是Object类的方法,sleep是Thread的静态方法
以上がJavaでスレッド間の通信を実装するためにwaitとnotifyを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは、特に迅速な開発や動的なコンテンツの処理に適していますが、データサイエンスとエンタープライズレベルのアプリケーションには良くありません。 Pythonと比較して、PHPはWeb開発においてより多くの利点がありますが、データサイエンスの分野ではPythonほど良くありません。 Javaと比較して、PHPはエンタープライズレベルのアプリケーションでより悪化しますが、Web開発により柔軟性があります。 JavaScriptと比較して、PHPはバックエンド開発により簡潔ですが、フロントエンド開発のJavaScriptほど良くありません。

PHPとPythonにはそれぞれ独自の利点があり、さまざまなシナリオに適しています。 1.PHPはWeb開発に適しており、組み込みのWebサーバーとRich Functionライブラリを提供します。 2。Pythonは、簡潔な構文と強力な標準ライブラリを備えたデータサイエンスと機械学習に適しています。選択するときは、プロジェクトの要件に基づいて決定する必要があります。

phphassiblasifly-impactedwebdevevermentandsbeyondit.1)itpowersmajorplatformslikewordpratsandexcelsindatabase interactions.2)php'sadaptableability allowsitale forlargeapplicationsusingframeworkslikelavel.3)

PHPが多くのWebサイトよりも優先テクノロジースタックである理由には、その使いやすさ、強力なコミュニティサポート、広範な使用が含まれます。 1)初心者に適した学習と使用が簡単です。 2)巨大な開発者コミュニティと豊富なリソースを持っています。 3)WordPress、Drupal、その他のプラットフォームで広く使用されています。 4)Webサーバーとしっかりと統合して、開発の展開を簡素化します。

PHPはWeb開発およびコンテンツ管理システムに適しており、Pythonはデータサイエンス、機械学習、自動化スクリプトに適しています。 1.PHPは、高速でスケーラブルなWebサイトとアプリケーションの構築においてうまく機能し、WordPressなどのCMSで一般的に使用されます。 2。Pythonは、NumpyやTensorflowなどの豊富なライブラリを使用して、データサイエンスと機械学習の分野で驚くほどパフォーマンスを発揮しています。
