マルチスレッドの待機通知メカニズム

目次
  • 待機通知メカニズムとは何ですか
  • 通知メカニズムの実現を待っています
  • notifyはロックオブジェクトをすぐには解放しません
  • 割り込みはスレッドの待機を中断します
  • notifyとnotifyAllの違い
  • 待機の使用(ロング)

待機通知メカニズムとは何ですか

クーポンプラットフォームhttps://www.cqfenfa.com/

シングルスレッドでは、実行する操作を実行する前に、特定の条件を満たす必要があります。この操作をifステートメントブロックに入れることができます。

マルチスレッドプログラミングでは、スレッドAの条件が満たされない場合がありますが、一時的にしか満たされません。後で他のスレッドBが条件を更新して、スレッドAの条件が満たされる場合があります。スレッドAは、条件が満たされるまで中断できます。スレッド目を覚ます

Atomic{
 while(条件不成立)
 {
 等待
 }
 条件满足后,当前线程被唤醒
}

通知メカニズムの実現を待っています

オブジェクトクラスのWaitメソッドは、通知または中断されるまで、現在のスレッドのコードの実行を一時停止させることができます。

注意:

(1)waitメソッドは、同期コードブロック内のロックオブジェクトからのみ呼び出すことができます。

(2)waitメソッドを呼び出すと、現在のスレッドがロックを解放します

public class Text16_5 {
    public static void main(String[] args) throws InterruptedException {
        String text="hello";
        System.out.println("同步前代码块");
        synchronized (text)
        {
            System.out.println("同步代码块开始");
            text.wait();
            System.out.println("同步代码块结束");
        }
        System.out.println("全部结束");
    }
}

画像-20210316211333325

ロックオブジェクトのwaitメソッドが呼び出されるため、ロックオブジェクトは解放され、待機状態になり、ウェイクアップされない場合は永久に待機します。

オブジェクトクラスのnotifyメソッドはスレッドをウェイクアップできます。このメソッドもコードブロックで同期する必要があります。ロックオブジェクトによって呼び出されます。ロックオブジェクトを使用せずにwait / notifyを呼び出すと、IiegalMonuitorStateExeption例外が報告されます。複数の待機中のスレッドの場合、notifyメソッドはそのうちの1つのみをウェイクアップできます。同期コードブロックでnotifyメソッドを呼び出した後、ロックオブジェクトはすぐには解放されません。現在の同期コードブロックが実行されるまで、ロックオブジェクトは解放されません。 。通常、notifyは同期されたコードブロックの最後に配置されます。

synchronized(锁对象)
{
  //执行修改保护条件的代码
  //唤醒其他线程
  锁对象.notify();
}
public class TextNotify {
    public static void main(String[] args) throws InterruptedException {
        String text="hello";
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (text)
                {
                    System.out.println("同步代码块开始");
                    try {
                        text.wait();//线程等待 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("同步代码块结束");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (text)
                {
                    System.out.println("线程开始唤醒");
                    text.notify();
                    System.out.println("线程结束唤醒");
                }
            }
        });
        t1.start();//开启t1线程 t1等待
        Thread.sleep(3000);//睡眠3秒 确保t1处于等待状态
        t2.start();//唤醒t1线程
    }
}

画像-20210316214002434

notifyはロックオブジェクトをすぐには解放しません

場合:

import java.util.ArrayList;
import java.util.List;

public class NotifyText2 {
    public static void main(String[] args) throws InterruptedException {
        List<String> strings=new ArrayList<>();
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (strings)
                {
                    System.out.println("线程1开始等待");
                    try {
                        strings.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1被唤醒");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
               synchronized (strings)
               {
                   for (int i = 0; i <10 ; i++) {
                       strings.add("data"+i);
                       System.out.println("线程2添加了"+(i+1));
                       if(strings.size()==5)
                       {
                           strings.notify();
                           System.out.println("线程2被唤醒");
                       }
                   }
               }
            }
        });
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

スレッド2のコードはまだ実行されておらず、ロックはすぐに解放されずに実行されています。すべてのコードブロックが実行されるまで待ってから解放する必要があります。

画像-20210316220423289

割り込みはスレッドの待機を中断します

public class InterruptText {
    private static  final String name=new String();
    public static void main(String[] args) throws InterruptedException {

        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (name)
                {
                    try {
                        System.out.println("同步代码块开始");
                        name.wait();
                        System.out.println("同步代码块结束");
                    } catch (InterruptedException e) {
                        System.out.println("wait被中断"+e);
                    }
                }
            }
        });
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();
    }
}

ロックオブジェクトを解放するには、ロックオブジェクトが同期コードブロックを実行する必要があることが判明しました。実行プロセス中に例外が発生した場合、スレッドは終了し、ロックオブジェクトが解放されます。waitメソッドを呼び出すと、ロックオブジェクトも解放されます。

画像-20210317202003190

notifyとnotifyAllの違い

Notifyは一度に1つしかウェイクアップできません。複数のスレッドが待機している場合、ランダムにウェイクアップできるのはそのうちの1つだけです。待機中のすべてのスレッドをウェイクアップするには、notifyAllを呼び出す必要があります。

public class InterruptText {
    private static  final String name=new String();
    public static void main(String[] args) throws InterruptedException {
        String str=new String();
        NotifyAll notifyAll=new NotifyAll(str);
        NotifyAll notifyAl2=new NotifyAll(str);
        NotifyAll notifyAll3=new NotifyAll(str);
        notifyAll.setName("线程一");
        notifyAl2.setName("线程二");
        notifyAll3.setName("线程三");
        notifyAll.start();
        notifyAl2.start();
        notifyAll3.start();
        Thread.sleep(2000);//休眠两秒
        synchronized (str)
        {
            //str.notify();只能随机唤醒一个
            str.notifyAll();//唤醒全部线程
        }
    };
     static class NotifyAll extends Thread
    {
        private    String name;
        private  NotifyAll(String name)
        {
            this.name=name;
        }
                @Override
                public void run() {
                    synchronized (name)
                    {
                        try {
                            System.out.println(Thread.currentThread().getName()+"同步代码块开始");
                            name.wait();
                            System.out.println(Thread.currentThread().getName()+"同步代码块结束");
                        } catch (InterruptedException e) {
                            System.out.println("wait被中断"+e);
                        }
                    }
                }

    }
}

画像-20210317221240524

notify()を1回だけ呼び出すという悪が、スレッドの1つをウェイクアップできる場合、他の待機中のスレッドはまだ待機状態にあり、通知シグナルが失われます。この現象はシグナル損失と呼ばれます。

待機の使用(ロング)

パラメータを使用したWait(Long)メソッド、指定された時間内の操作は自動的に起動されません

おすすめ

転載: blog.csdn.net/nidongla/article/details/115029321