コードのデモ:
/** * <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
メソッドを呼び出した後、現在のスレッド (通常はメイン スレッド) は、JVM 仮想マシンが空いている場合にこれを開始するように要求します。糸。 start
メソッドを実行しても、スレッドをすぐに開始できない場合があります。 srtart
メソッドが呼び出された後、このメソッドの実行が開始されたわけではありません。後で実行されるまで実行されない場合や、飢餓の場合など、長期間実行されない場合があります。 start
メソッドを呼び出し、次にスレッド 2 が start
メソッドを呼び出しても、最初にスレッド 2 が見つからないことも証明しています。スレッド1を実行した後の実行状況。 start
メソッドが呼び出される順序は、実際のスレッドが実行される順序を決定しません。 メソッドには 2 つのスレッドが関係します。
メソッドを実行するにはメイン スレッドまたは他のスレッド (メイン スレッドでない場合でも) が必要であるため、2 番目のスレッドは次のとおりです。新しいものはルートです。
の呼び出しがすでに子スレッドによって実行されていると誤解しないでください。このステートメントは実際にはメインスレッドまたはメインスレッド。親スレッドによって実行され、実行後に新しいスレッドが作成されます。
新しいスレッドを作成する方法準備
コード例
/** * <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(); } }复制代码
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's list of threads * and the group'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 */ } } }复制代码
if (threadStatus != 0) throw new IllegalThreadStateException();复制代码
このうち、 threadStatus この変数のアノテーションは次のとおりです。これは、Java スレッドのステータスが最初は 0 (まだ開始されていない) として表現されることを意味します。 :
/* Java thread status for tools, * initialized to indicate thread 'not yet started' */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(); } }复制代码
メソッドをオーバーライドする。 Thread
の run
メソッドは無効になり、オーバーライドされた run
メソッドが実行されます。
2 番目のタイプ: target
オブジェクト (つまり、Runnable
インターフェイスの実装) を渡し、Thread の元の # を実行します。
##run メソッドは、
target オブジェクトの
run メソッドの実行に進みます。
メソッドは通常のメソッドであり、直接実行されます。つまり、自分で書いた通常のメソッドを実行するのと同じなので、その実行スレッドがメインスレッドになります。
したがって、実際にスレッドを開始したい場合は、
run メソッドを呼び出す必要があります。 ##実行## 間接的に # メソッドを実行します。
Java の基礎
以上がJava でスレッドを開始する正しい方法と間違った方法を詳しく見るの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。