以下のエディターでは、Java スレッド間の待機/通知通信について簡単に説明します。編集者はこれがとても良いものだと思ったので、皆さんの参考として今から共有します。エディターに従って見てみましょう。Java の Wait/notify/notifyAll は、オブジェクト クラスのメソッドであり、プラットフォームに関連するものです。プロデューサー/コンシューマー パターンを実装するために使用されます。まず、関連する定義を見てみましょう:
このメソッドを呼び出すスレッドは、wait( を呼び出した後、別のスレッドからの通知または割り込みを待った後にのみ戻ります。 ) メソッドを実行すると、オブジェクトのロックが解除されます。 wait(long):
通知がない場合は、最長でミリ秒間待機します。 notify():
wait() メソッドから戻るオブジェクトを待っているスレッドに通知します。戻りの前提は、スレッドがオブジェクトのロックを取得することです。 notifyAll():
このオブジェクトを待機しているすべてのスレッドに通知します。 簡単な例をシミュレーションしてみましょう。 階下に小さな餃子レストランがあります。毎回調理する 1 食分をウェイターが 1 食分持ってくるのでは、あまりにも非効率でエネルギーの無駄です。ここで、シェフが 10 人前を準備するたびに、ウェイターが大きな木の皿にそれを盛り付けて顧客に提供するとします。毎日 100 人前を販売した後、レストランは閉店し、シェフとウェイターは家に帰って休憩します。
考えてみてください、この機能を実装するために、待機/通知メカニズムを使用しない場合、最も直接的な方法は、ウェイターが時々キッチンに行って皿に 10 人分取り出すことかもしれません。 この方法には 2 つの大きな欠点があります:
1. ウェイターがキッチンに行きすぎて疲れすぎている場合は、ボウルを作るたびにゲストに提供する方が良いです。 Damu プレートの機能が反映されません。実装コード レベルでの具体的な兆候は、継続的なループが必要となり、プロセッサ リソースが無駄になるということです。
2. ウェイターが時間が経ってからキッチンに確認に行くと、シェフがすでに 10 食分を作っていたのに、ウェイターがそれを守らなかった可能性があります。 上記の例では、待機/通知メカニズムを使用する方がはるかに合理的です。シェフは 10 個分を作るたびに、「餃子ができました。お持ち帰りできます。」と叫びます。通知を受け取ると、ウェイターは厨房に行き、餃子をゲストに提供します。シェフはまだ十分ではない、つまりシェフからの通知を受け取っていないため、少し休憩することができます。彼はまだ耳を澄ましてシェフからの通知を待たなければなりません。 package ConcurrentTest;
import thread.BlockQueue;
/**
* Created by chengxiao on 2017/6/17.
*/
public class JiaoziDemo {
//创建个共享对象做监视器用
private static Object obj = new Object();
//大木盘子,一盘最多可盛10份饺子,厨师做满10份,服务员就可以端出去了。
private static Integer platter = 0;
//卖出的饺子总量,卖够100份就打烊收工
private static Integer count = 0;
/**
* 厨师
*/
static class Cook implements Runnable{
@Override
public void run() {
while(count<100){
synchronized (obj){
while (platter<10){
platter++;
}
//通知服务员饺子好了,可以端走了
obj.notify();
System.out.println(Thread.currentThread().getName()+"--饺子好啦,厨师休息会儿");
}
try {
//线程睡一会,帮助服务员线程抢到对象锁
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--打烊收工,厨师回家");
}
}
/**
* 服务员
*/
static class Waiter implements Runnable{
@Override
public void run() {
while(count<100){
synchronized (obj){
//厨师做够10份了,就可以端出去了
while(platter < 10){
try {
System.out.println(Thread.currentThread().getName()+"--饺子还没好,等待厨师通知...");
obj.wait();
BlockQueue
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//饺子端给客人了,盘子清空
platter-=10;
//又卖出去10份。
count+=10;
System.out.println(Thread.currentThread().getName()+"--服务员把饺子端给客人了");
}
}
System.out.println(Thread.currentThread().getName()+"--打烊收工,服务员回家");
}
}
public static void main(String []args){
Thread cookThread = new Thread(new Cook(),"cookThread");
Thread waiterThread = new Thread(new Waiter(),"waiterThread");
cookThread.start();
waiterThread.start();
}
}
cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--饺子还没好,等待厨师通知... cookThread--饺子好啦,厨师休息会儿 waiterThread--服务员把饺子端给客人了 waiterThread--打烊收工,服务员回家 cookThread--打烊收工,厨师回家
動作メカニズム
wait/notifyの動作メカニズムを理解するには、「The Art of Concurrency
Programming」から画像を借用してください
誰か教えてくださいいわゆるモニターとオブジェクトのロックについてはあまり知りません。簡単に説明すると、
jvm は、オブジェクトとクラスをロックすることを意味します。
オブジェクト ロックが取得された場合にのみ、モニターを取得できます。ロックの取得が失敗した場合、スレッドはブロック キューに入ります。オブジェクト ロックの取得に成功した場合は、wait() メソッドを使用して待機することもできます。このとき、ロックは解放され、待機キューに入ります。 ロックとモニターの違いについては、非常に詳細で徹底的な記事があるので、ここに引用します。興味のあるお子様はそれについて学ぶことができます ロックとモニターの違いについて詳しく説明します_Java Concurrency
。上の図を基に、具体的な処理を整理してみましょう
1. まず、waitThread がオブジェクトのロックを取得し、次に wait() メソッドを呼び出します。このとき、待機スレッドはオブジェクトのロックを放棄し、オブジェクトの待機キュー WaitQueue に入る
2. NoticeThread スレッドはオブジェクトのロックを取得し、いくつかの操作を実行し、notify() メソッドを呼び出します。このとき、待機スレッド waitThread は待機キュー WaitQueue に移動されます。 SynchronizedQueue をキューに追加すると、waitThread が待機状態からブロック状態に変わります。この時点では、notifyThread はすぐにロックを解放しないことに注意してください。実行は継続され、残りの作業が完了した後にロックが解放されます。3. waitThread は再度オブジェクト ロックを取得し、wait() メソッドから戻ります。以降の操作を続行します。 4. 待機/通知メカニズムに基づくスレッド間通信のプロセスが終了します。
notifyAll に関しては、2 番目のステップで、待機キュー内のすべてのスレッドが同期キューに移動されます。
落とし穴を避けてください
wait/notify/notifyAll を使用する場合は、注意すべき特別な点がいくつかあります。概要は次のとおりです。
1 必ず wait()/notify()/notifyAll() を使用してください。前述したように、ロックがロックされた後にのみモニターを取得できるため、最初にロックを取得する必要があることを意味します。それ以外の場合、jvm は IllegalMonitorStateException もスローします。
2. wait() を使用する場合、スレッドが待機状態に入るかを決定する条件は if ではなく while を使用する必要があります。待機中のスレッドが誤って起動される可能性があるため、待機の前後に while ループ を使用する必要があります。安全を確保するためにウェイクアップ条件が満たされているかどうかを確認してください。
3. Notice() メソッドまたは NotifyAll() メソッドが呼び出された後、スレッドはすぐにはロックを解放しません。この呼び出しは、待機中のスレッドを待機キューから同期キューに移動するだけです。つまり、スレッドのステータスが待機状態からブロック状態に変わります。
4 メソッドから戻る前提は、スレッドが待機状態を取り戻すことです。呼び出し元オブジェクトのロック。
追記
今回はwait/notifyの紹介ですが、実際に使用する際は上記の点に特に注意してください。ただし、通常はスレッド間で完了するためにwait/notify/notifyAllを使用します。 Java 同時実行パッケージには、さまざまな BlockingQueue などの優れた優れたツールがすでに提供されているため、プロデューサー/コンシューマー モデルの機会はそれほど多くありません。これについては、後で機会があれば詳しく紹介します。
以上がJavaスレッド間通信のwait/notifyインスタンスの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。