Javaスレッドでstartメソッドとrunメソッドを使用する方法

WBOY
リリース: 2023-04-20 08:58:06
転載
1591 人が閲覧しました

    start メソッドと run メソッド

    $start()$ メソッドは、スレッドの開始に使用されます。この時点で、スレッドは ready になっています。 (Runnable) 状態、実行中ではありません $cpu$ タイム スライスが取得されると、$run()$ メソッドの実行が開始されます。 $run()$ メソッドを直接呼び出すと、クラス内のメソッドが呼び出されるだけであり、このメソッドは基本的に現在のスレッドで実行されるため、$start()$ メソッドを使用して $run()$ を呼び出すことによってのみ実現できます。メソッド。真のマルチスレッド。

    サンプル コード

    @Slf4j(topic = "c.Test4")
    public class Test4 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("running");
                }
            };
            t1.run();
        }
    }
    ログイン後にコピー

    上記のコードは、$run()$ メソッドへの直接呼び出しです。出力された情報から、$main$ スレッドがこのメソッドを実行したことがわかります。

    @Slf4j(topic = "c.Test4")
    public class Test4 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("running");
                }
            };
            t1.start();
        }
    }
    ログイン後にコピー

    $start()$ メソッドを使用して開始する場合、それは $t1$ スレッドによって実行される実際の $run$ メソッドです。

    Note

    $Thread$ オブジェクトが $start()$ メソッドを呼び出すと、準備完了状態になることに注意してください。 () を呼び出すことはできません。$ メソッドを呼び出すと、次のコードに示すように、$IllegalThreadStateException$ 例外がスローされます。

    @Slf4j(topic = "c.Test4")
    public class Test4 {
        public static void main(String[] args) {
            Thread t1 = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("running");
                }
            };
            t1.start();
            t1.start();
        }
    }
    ログイン後にコピー

    例外情報:

    Javaスレッドでstartメソッドとrunメソッドを使用する方法

    sleep メソッド yield メソッドを使用した場合

    #sleep

    • $sleep()$ メソッドを呼び出すと、現在のスレッドが $Running$ 状態から$Time Waiting$ 状態 (ブロック)

    • 他のスレッドは、$interrupt$ メソッドを使用して、スリープ状態のスレッドに割り込むことができます。このとき、$sleep$ メソッドは InterruptedException## をスローします。

    • #スリープ後 スレッドはすぐには実行されない可能性があります

    • $Thread$' の代わりに $TimeUnit$ の $sleep$ を使用することをお勧めします■ 可読性を高めるための $sleep$ サンプルコード

    • @Slf4j(topic = "c.Test5")
      public class Test5 {
          public static void main(String[] args) {
              Thread t1 = new Thread("t1"){
                  @Override
                  public void run() {
                      try {
                          Thread.sleep(2000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              };
              t1.start();
              log.debug("t1 state {}", t1.getState());
              //让主线程休眠500ms
              try {
                  Thread.sleep(500);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              log.debug("t1 state {}", t1.getState());
          }
      }
      //17:13:21.729 [main] DEBUG c.Test5 - t1 state RUNNABLE
      //17:13:22.245 [main] DEBUG c.Test5 - t1 state TIMED_WAITING
      ログイン後にコピー
    上記のコードでは、最初に $t1$ スレッドが開始されます。このとき、印刷スレッドの状態は$RUNNABLE$ 状態になり、メイン スレッドをスリープ状態にすると、メイン スレッドが最初に印刷を実行することはなくなりますが、まだ $sleep()$ 状態にはなっていません。 $run()$ の $sleep$ メソッドが実行されると、スレッドは $TIMED WAITING$ 状態に入ります。

    #

    @Slf4j(topic = "c.Test6")
    public class Thread6 {
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread("t1") {
                @Override
                public void run() {
                    try {
                        log.debug("enter sleep");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        log.debug("wake up");
                        e.printStackTrace();
                    }
                }
            };
            t1.start();
            Thread.sleep(1000);
            log.debug("interrupt t1");
            //被唤醒
            t1.interrupt();
        }
    }
    ログイン後にコピー

    実行結果

    Javaスレッドでstartメソッドとrunメソッドを使用する方法

    上記のコードでは、$start$ メソッドが開始されると、$t1$ スレッドはスリープ状態に入り、プロンプト情報を出力します。スリープ時間は $2s$ で、$1s$ スリープした後に $t1$ を中断します。 $main$ スレッド内で、スレッドがスリープ状態になると、割り込みメッセージが表示され、$interrupt()$ メソッドが呼び出されます。このとき、スレッドは中断され、例外がスローされます。

    Javaスレッドでstartメソッドとrunメソッドを使用する方法

    $TimeUnit$ クラスは、睡眠のための新しい単位を追加します。これにより読みやすくなりますが、本質的に違いはなく、単位の変換

    TimeUnit.SECONDS.sleep(1);//该语句作用是睡眠一秒
    ログイン後にコピー

    yield だけです。

    $yield$ を呼び出すと、現在のプロセスが $Running$ から $Runnable$ 準備完了状態になり、他のスレッドをスケジュールして実行します。具体的な実装はオペレーティング システムのタスク スケジューラによって異なります。(つまり、タスク スケジューラに他のタスクがない場合、$cpu$ が放棄されてもスレッドは実行を継続します) $sleep$ は実行後にブロック状態に入ります。今回は、$cpu$ はスレッドに割り当てられませんが、$yield$ は準備完了状態に入ります。つまり、他のスレッドを実行する必要がない場合、スレッドにはタイム スライスも割り当てられます。これが最大です。 $sleep$ と $yield$ の違い。スレッド優先度

    スレッド優先度

    は、最初にスレッドをスケジュールするようにスケジューラにプロンプ​​トを表示しますが、これは単なるプロンプトであり、スケジューラはそれを無視できます

    $cpu$ がビジーな場合、優先度の高い方がより多くのタイム スライスを取得しますが、$cpu$ がアイドル状態の場合、優先度はほとんどありません

    スリープ アプリケーションで CPU が 100% を占有するのを防ぎます

    $cpu$ が計算に使用されない場合、$while(true )$ のアイドリングによって $cpu$ が無駄にならないようにしてください。このとき、$yield$ または $sleep$ を使用して $ の使用を引き継ぐことができます。

    while (true) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
      }
    }
    ログイン後にコピー

    $wait$ または条件変数を使用して同様の結果を達成できます効果

    違いは、後者の 2 つはロックと対応するウェイクアップ操作を必要とすることです。同期が必要なシナリオに適しています
    $sleep$はロック同期が必要ないシナリオに適しています

    joinメソッド

    次のプログラムの結果を出力します:

    @Slf4j(topic = "c.Test6")
    public class Test6 {
        static int r = 0;
        public static void main(String[] args) {
            test();
        }
        private static void test() {
            log.debug("开始");
            Thread t = new Thread("t1") {
                @Override
                public void run() {
                    log.debug("开始");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.debug("结束");
                    r = 10;
                }
            };
            t.start();
            log.debug("r的值是{}", r);
            log.debug("结束");
        }
    }
    ログイン後にコピー

    Javaスレッドでstartメソッドとrunメソッドを使用する方法

    メイン スレッドと $t1$ スレッドは並列であるため、$t1$ スレッドが $r$ の値を計算するのに $1s$ かかり、メインスレッドは最初に $r$ の値を出力するため、出力される値は 0

    解決策:

    $t.join();$ を後に追加します。 $t.start();$。 $join$ の機能は、スレッドの実行が終了するのを待つことです。

    呼び出し元の観点から見ると、結果が返されるのを待ってから実行を続行するのは同期であり、結果が返されるのを待たずに実行を続行するのは非同期です。

    Javaスレッドでstartメソッドとrunメソッドを使用する方法

    つまり、$join$ メソッドを使用すると、実際には同期的に実行できます。

    効果的な待機

    $join(ミリ秒)$ メソッドがあります。スレッドの実行時間が待機時間よりも長い場合、待機時間が経過すると待機を停止します。スレッドの実行時間が待機時間未満の場合は、スレッドの実行完了後に待機が終了します。設定した待ち時間は経過しません。

    interrupt方法

    打断$sleep, wait, join$的线程,即打断阻塞状态的线程
    打断$sleep$的线程,会清空打断状态

    @Slf4j(topic = "c.Test7")
    public class Test7 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread("t1"){
                @Override
                public void run() {
                    log.debug("sleep...");
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            t.start();
            Thread.sleep(1000);
            log.debug("interrupt");
            t.interrupt();
            log.debug("打断标记: {}", t.isInterrupted());
        }
    }
    ログイン後にコピー

    Javaスレッドでstartメソッドとrunメソッドを使用する方法

    打断正常运行的线程,不会清空打断状态

    因此我们可以在线程中判断打断标记,来决定是否被打断,以及执行被打断之前的收尾工作。

    @Slf4j(topic = "c.Test8")
    public class Test8 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread("t1"){
                @Override
                public void run() {
                    while (true) {
                        if (Thread.currentThread().isInterrupted()) {
                            log.debug("线程被打断了");
                            break;
                        }
                    }
                }
            };
            t.start();
            Thread.sleep(1000);
            log.debug("interrupt");
            t.interrupt();
        }
    }
    ログイン後にコピー

    守护线程

    默认情况下,$java$需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完毕,也会强制结束。

    @Slf4j(topic = "c.Test10")
    public class Test10 {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread("t1") {
                @Override
                public void run() {
                    while (true) {
    
                    }
                }
            };
            //设置线程为守护线程
            t.setDaemon(true);
            t.start();
            Thread.sleep(1000);
            log.debug("主线程结束");
        }
    }
    ログイン後にコピー

    如果不把$t$设置为守护线程,则因为线程内部的死循环,导致程序不会结束运行。

    以上がJavaスレッドでstartメソッドとrunメソッドを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート