ホームページ  >  記事  >  Java  >  Java でスレッドを開始する正しい方法と間違った方法を詳しく見る

Java でスレッドを開始する正しい方法と間違った方法を詳しく見る

coldplay.xixi
coldplay.xixi転載
2020-09-28 16:55:092116ブラウズ

Java でスレッドを開始する正しい方法と間違った方法を詳しく見る

Java でスレッドを開始する正しい方法と誤った方法を詳しく見る

前の記事のレビュー

  1. Java でマルチスレッドを実装するメソッドはいくつありますか? (本質に基づく)

start メソッドと run メソッドの比較

コードのデモ:

/**
 * <p>
 * start() 和 run() 的比较
 * </p>
 *
 * @author 踏雪彡寻梅
 * @version 1.0
 * @date 2020/9/20 - 16:15
 * @since JDK1.8
 */public class StartAndRunMethod {    public static void main(String[] args) {        // run 方法演示
        // 输出: name: main
        // 说明由主线程去执行的, 不符合新建一个线程的本意
        Runnable runnable = () -> {
            System.out.println("name: " + Thread.currentThread().getName());
        };
        runnable.run();        // start 方法演示
        // 输出: name: Thread-0
        // 说明新建了一个线程, 符合本意
        new Thread(runnable).start();
    }
}复制代码

上記の例から、次の 2 つの点が分析できます。

  • run メソッドを直接使用しても、新しいスレッドは開始されません。 (間違った方法)

  • start メソッドは新しいスレッドを開始します。 (正しいやり方)

startメソッド分析

startメソッドの意味と注意点

  • start メソッドは新しいスレッドを開始できます。

    • スレッド オブジェクトが初期化後に start メソッドを呼び出した後、現在のスレッド (通常はメイン スレッド) は、JVM 仮想マシンが空いている場合にこれを開始するように要求します。糸。
    • 言い換えれば、新しいスレッドを開始する本質は、JVM にスレッドの実行を要求することです。
    • このスレッドがいつ実行できるかについては、私たちが単純に決定するのではなく、スレッド スケジューラによって決定されます。
    • 非常に混雑している場合、start メソッドを実行しても、スレッドをすぐに開始できない場合があります。
    • したがって、srtart メソッドが呼び出された後、このメソッドの実行が開始されたわけではありません。後で実行されるまで実行されない場合や、飢餓の場合など、長期間実行されない場合があります。
    • これは、場合によっては、スレッド 1 が最初に start メソッドを呼び出し、次にスレッド 2 が start メソッドを呼び出しても、最初にスレッド 2 が見つからないことも証明しています。スレッド1を実行した後の実行状況。
    • 概要: start メソッドが呼び出される順序は、実際のスレッドが実行される順序を決定しません。
    • #注
      • start メソッドには 2 つのスレッドが関係します。
      • 最初のスレッドはメイン スレッドです。この
      • start メソッドを実行するにはメイン スレッドまたは他のスレッド (メイン スレッドでない場合でも) が必要であるため、2 番目のスレッドは次のとおりです。新しいものはルートです。
      • 多くの場合、スレッドを作成するメイン スレッドは無視されます。
      • start の呼び出しがすでに子スレッドによって実行されていると誤解しないでください。このステートメントは実際にはメインスレッドまたはメインスレッド。親スレッドによって実行され、実行後に新しいスレッドが作成されます。
  • #start

    新しいスレッドを作成する方法準備

    まず、スレッドを作成します。準備完了状態。
    • 準備完了状態は、コンテキスト、スタック、スレッド ステータス、PC (PC はレジスタ、PC はプログラムが実行されている場所を指します) など、CPU 以外の他のリソースが取得されていることを意味します。 . が設定されています。
      これらの準備が完了すると、準備は完了です。必要なのは CPU リソースである Dongfeng だけです。
    • 準備作業が完了したら、JVM またはオペレーティング システムによってスレッドをさらに実行状態にスケジュールして CPU リソースを待機することができ、実際に実行状態になって
    • run を実行します。
    • メソッド.コード。
  • #注: start メソッドは繰り返し実行できません
  • コード例
      /**
      * <p>
      * 演示不能重复的执行 start 方法(两次及以上), 否则会报错
      * </p>
      *
      * @author 踏雪彡寻梅
      * @version 1.0
      * @date 2020/9/20 - 16:47
      * @since JDK1.8
      */public class CantStartTwice {    public static void main(String[] args) {
              Runnable runnable = () -> {
                  System.out.println("name: " + Thread.currentThread().getName());
              };
              Thread thread = new Thread(runnable);        // 输出: name: Thread-0
              thread.start();        // 输出: 抛出 java.lang.IllegalThreadStateException
              // 即非法线程状态异常(线程状态不符合规定)
              thread.start();
          }
      }复制代码
    • エラーの原因
    • start
        実行が開始されると、スレッドの状態は初期の New 状態 (Runnable など) から次の状態に入り、その後スレッドが実行を完了すると、スレッドは終了状態になり、終了状態に戻ることはできないため、上記の例外がスローされます。これは、初期状態に戻ることができないことを意味します。ここでの説明は十分に明確ではないため、ソース コードを見てさらに詳しく理解しましょう。
    • #メソッドのソースコード解析開始
  • ソースコード
public synchronized void start() {    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
    // 第一步, 检查线程状态是否为初始状态, 这里也就是上面抛出异常的原因
    if (threadStatus != 0)        throw new IllegalThreadStateException();    /* Notify the group that this thread is about to be started
     * so that it can be added to the group&#39;s list of threads
     * and the group&#39;s unstarted count can be decremented. */
    // 第二步, 加入线程组
    group.add(this);    boolean started = false;    try {        // 第三步, 调用 start0 方法
        start0();
        started = true;
    } finally {        try {            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}复制代码

ソースコード内の処理

ステップ 1:

新しいスレッドを開始すると、最初にスレッドの状態が初期状態であるかどうかがチェックされます。これが、上記の例外がスローされる理由でもあります。つまり、次のコードです。

if (threadStatus != 0)    throw new IllegalThreadStateException();复制代码

このうち、 threadStatus この変数のアノテーションは次のとおりです。これは、Java スレッドのステータスが最初は 0 (まだ開始されていない) として表現されることを意味します。 :

/* Java thread status for tools,
 * initialized to indicate thread &#39;not yet started&#39;
 */private volatile int threadStatus = 0;复制代码

ステップ 2:スレッド グループに追加します。つまり、次のコードです。

group.add(this);复制代码

3 番目のステップ:最後に

start0()

を呼び出します。このネイティブ メソッド (ネイティブとは、そのコードが Java によって実装されていないことを意味します。ただし、C/C 実装によって、具体的な実装は JDK で確認できます。理解してください)、つまり、次のコードです:

boolean started = false;try {    // 第三步, 调用 start0 方法
    start0();
    started = true;
} finally {    try {        if (!started) {
            group.threadStartFailed(this);
        }
    } catch (Throwable ignore) {        /* do nothing. If start0 threw a Throwable then
          it will be passed up the call stack */
    }
}复制代码
メソッド分析の実行メソッド ソース コード分析の実行

@Overridepublic void run() {    // 传入了 target 对象(即 Runnable 接口的实现), 执行传入的 target 对象的 run 方法
    if (target != null) {
        target.run();
    }
}复制代码

run メソッドの 2 つの状況

最初の状況:

Thread
    クラスの
  • run

    メソッドをオーバーライドする。 Threadrun メソッドは無効になり、オーバーライドされた run メソッドが実行されます。

  • 2 番目のタイプ: target オブジェクト (つまり、Runnable インターフェイスの実装) を渡し、Thread の元の # を実行します。 ##run メソッドは、target オブジェクトの run メソッドの実行に進みます。

  • 概要:

    • #run メソッドは通常のメソッドであり、直接実行されます。つまり、自分で書いた通常のメソッドを実行するのと同じなので、その実行スレッドがメインスレッドになります。 したがって、実際にスレッドを開始したい場合は、run
    • メソッドを直接呼び出すことはできませんが、# を呼び出すことができる
    • start メソッドを呼び出す必要があります。 ##実行## 間接的に # メソッドを実行します。
    関連する学習の推奨事項:
Java の基礎

以上がJava でスレッドを開始する正しい方法と間違った方法を詳しく見るの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.imで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。