ホームページ  >  記事  >  Java  >  Java スレッドの 6 つの状態とライフサイクルとは何ですか?

Java スレッドの 6 つの状態とライフサイクルとは何ですか?

王林
王林転載
2023-05-02 12:07:061344ブラウズ

    1. スレッドの状態 (ライフサイクル)

    スレッドは、特定の時点で 1 つの状態にのみなりえます。

    スレッドには次の 6 つの状態があります:

    • New (新しく作成された): 未開始のスレッド;

    • Runnable (実行可能) ): オペレーティング システムのリソースを待機する必要がある実行可能なスレッド;

    • Blocked (ブロック済み): モニター ロックの待機中にブロックされたスレッド;

    • Waiting (待機中): ウェイクアップ状態を待機し、別のスレッドがウェイクアップするまで無期限に待機します;

    • 時間制限された待機 (時間制限された待機): 指定された時間内で待機します。待機時間 別のスレッドが操作を実行するスレッド;

    • 終了: 終了したスレッド。

    スレッドの現在の状態を確認するには、getState メソッドを呼び出すことができます。

    スレッド状態の関係図

    注: 点線のボックス (すべて大文字の英語) ステータスは Java スレッドのステータスです。

    Java スレッドの 6 つの状態とライフサイクルとは何ですか?

    2. 操作スレッドのステータス

    2.1. 新規作成ステータス (NEW)

    は、スレッドのインスタンス化が完了した後のことを意味します、スレッドは開始されていないステータスです。

    スレッドは 3 つの方法で作成できます

    • Thread クラスの run() メソッドをオーバーライドします

    • Runnable インターフェイスを実装します

    • Callable インターフェイスの実装

    3 つのメソッドをまとめた簡単な例です

    public class Demo {
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            /**
             * 1.直接重写run() 或继承Thread类再重写run()
             */
            Thread thread = new Thread() {
                @Override
                public void run() {
                    System.out.println("Thread");
                }
            };
            // 开启线程
            thread.start();
    
            /**
             * 2.lambda、内部类或线程类方式实现Runnable接口,实现run()方法
             * 再交给Thread 类
             */
            Thread runThread = new Thread(() -> {
                System.out.println("Runnable");
            });
            // 开启线程
            runThread.start();
    
            /**
             * 3.lambda、内部类或线程类方式实现Callable接口,实现call()方法
             * 再交给Thread 类:FutureTask本质也是Runnable实现类
             */
            FutureTask<String> futureTask = new FutureTask<String>(() -> {
                System.out.println("Callable");
                return "CallableThread";
            });
            Thread callThread = new Thread(futureTask);
            // 开启线程
            callThread.start();
            // 获取call()方法的返回值
            String s = futureTask.get();
            System.out.println("call()方法的返回值:"+s);
        }
    
    }

    run() または call() を書き換えないでくださいこのメソッドは、Thread クラスによって作成されたスレッドを直接インスタンス化しますが、実際的な意味はありません。

    Callable メソッドで作成されたスレッドのみが、スレッドの戻り値を取得できます。

    2.2. 実行可能状態 (RUNNABLE)

    この状態は、スレッドがオブジェクトをインスタンス化し、start() メソッドを呼び出した後に入る状態を指します。スレッドは実行可能な状態であり、プロセッサなどのリソースがあればプログラムを実行することができます。

    この状態には、オペレーティング システム レベルで 2 つのステップ (スレッド準備完了とスレッド実行中) が含まれていますが、Java スレッド状態では、これら 2 つのステップをまとめて Runnable (実行可能) 状態と呼びます。

    スレッドは準備完了状態から実行状態に変わります。重要な点は、スレッドが CPU リソース (CPU タイム スライス) を取得したかどうかを確認することです。取得した人がそれを実行します。取得しなかった場合は実行されます。つかまないで、待ってください。 CPU タイムスライス (実行時間) は約 10 ミリ秒と非常に短いため、スレッドの切り替え時間は非常に短く、準備完了状態から実行状態に移行する時間も非常に短く、この状態は実行中にほとんど見えません。そのため、Java では、スレッドが実行できるかどうかに焦点を当て、スレッドを他の状態と区別して、この 2 つを全体としてみなし、スレッドの開発をさらに簡素化します。プログラムを長時間実行する必要があり (無限ループの作成など)、その実行が CPU タイム スライス内に完了しない場合、スレッドは次の CPU タイム スライスを取得する必要があります。プログラムの実行を継続します。取得していない場合は、プログラムの実行を継続できます。その後、スレッド内のプログラムの実行が完了するまで取得を続ける必要があります。

    実際、このシナリオは以前にも見たことがあると思います。たとえば、複数のスレッドが同じプログラムを実行し、ログを同じファイルに出力する場合、異なるスレッドのログが混在するため、トラブルシューティングの質問です。この問題を解決する一般的な方法は、まずログを異なるスレッドの異なるファイルに出力すること、次にログ情報を文字列オブジェクトに保存し、プログラムの終了時に一度にログ情報をファイルに出力することです。 2 番目の方法は、CPU のタイム スライスを使用してログ情報の出力を完了する方法です。

    注: プログラムは、新しく作成された状態のスレッドでのみ start() メソッドを呼び出すことができます。新しく作成されていない状態のスレッドでは start() メソッドを呼び出さないでください。これにより、IllegalThreadStateException 例外が発生します。

    2.3. ブロック状態 (BLOCKED)

    スレッドは

    monitor ロック を待機しており、ブロックされています。 1 つのスレッドがロックを取得したが解放せず、他のスレッドもロックを取得しに来ましたが、ロックを取得できずにブロック状態になりました。 ブロックされた状態は、複数のスレッドによる同時アクセス下でのみ存在します。これは、スレッド自体が「待機」状態になることによって引き起こされる後者の 2 つのタイプのブロックとは異なります。

    状態を入力してください

      同期されたコード ブロック/メソッドを入力してください
    • ロックが取得されていません
    終了ステータス

      モニターロックを取得しました
    • 2.4. ウェイクアップを待ちますstate (WAITING)

    プロセス全体は次のようになります: スレッドは最初にオブジェクトの同期メソッドでオブジェクト ロックを取得し、wait メソッドが実行されると、スレッドはオブジェクト ロックを解放し、スレッドはこのオブジェクトの待機キューに入ります。別のスレッドが同じオブジェクトのロックを取得するのを待ち、その後、notify() または NoticeAll() メソッドを通じてオブジェクトの待機キュー内のスレッドをウェイクアップします。

    プロセス全体からわかるように、

    wait ()、notify ()、notifyAll () メソッドは、スレッドが実行を続行する前にロックを取得する必要があるため、これら 3 つのメソッドは次のようになります。必須 実行のために同期されたコード ブロック/メソッドに配置します。そうでない場合は、例外 java.lang.IllegalMonitorStateException が報告されます。

    在同步代码块中,线程进入WAITING 状态时,锁会被释放,不会导致该线程阻塞。反过来想下,如果锁没释放,那其他线程就没办法获取锁,也就没办法唤醒它。

    进入状态

    • object.wait()

    • thread.join()

    • LockSupport.park()

    退出状态

    • object.notify()

    • object.notifyall()

    • LockSupport.unpark()

    2.5.计时等待状态(TIMED_WAITING)

    一般是计时结束就会自动唤醒线程继续执行后面的程序,对于Object.wait(long) 方法还可以主动通知唤醒。

    注意:Thread类下的sleep() 方法可以放在任意地方执行;而wait(long) 方法和wait() 方法一样,需要放在同步代码块/方法中执行,否则报异常:java.lang.IllegalMonitorStateException。

    进入状态

    • Thread.sleep(long)

    • Object.wait(long)

    • Thread.join(long)

    • LockSupport.parkNanos(long)

    • LockSupport.parkNanos(Object blocker, long nanos)

    • LockSupport.parkUntil(long)

    • LockSupport.parkUntil(Object blocker, long deadline)

    注:blocker 参数为负责此线程驻留的同步对象。

    退出状态

    • 计时结束

    • LockSupport.unpark(Thread)

    • object.notify()

    • object.notifyall()

    2.6.终止(TERMINATED)

    线程执行结束

    • run()/call() 执行完成

    • stop()线程

    • 错误或异常>>意外死亡

    stop() 方法已弃用。

    3.查看线程的6种状态

    通过一个简单的例子来查看线程出现的6种状态。

    案例

    public class Demo3 {
        private static Object object ="obj";
        
        public static void main(String[] args) throws InterruptedException {
    
            Thread thread0 = new Thread(() -> {
                try {
                    // 被阻塞状态(BLOCKED)
                    synchronized (object){
                        System.out.println("thread0 进入:等待唤醒状态(WAITING)");
                        object.wait();
                        System.out.println("thread0 被解除完成:等待唤醒状态(WAITING)");
                    }
                    System.out.println("thread0 "+Thread.currentThread().getState());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            // 新创建状态(NEW)
            System.out.println(thread0.getName()+":"+thread0.getState());
    
            Thread thread1 = new Thread(() -> {
                try {
                    System.out.println("thread1 进入:计时等待状态(TIMED_WAITING)");
                    Thread.sleep(2);
                    System.out.println("thread1 出来:计时等待状态(TIMED_WAITING)");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 被阻塞状态(BLOCKED)
                synchronized (object){
                    System.out.println("thread1 解除:等待唤醒状态(WAITING)");
                    object.notify();
                    System.out.println("thread1 解除完成:等待唤醒状态(WAITING)");
                }
                System.out.println("thread1 "+Thread.currentThread().getState());
            });
            // 新创建状态(NEW)
            System.out.println(thread1.getName()+":"+thread1.getState());
    
            printState(thread0);
            printState(thread1);
    
            // 可运行状态(RUNNABLE)
            thread0.start();
            // 可运行状态(RUNNABLE)
            thread1.start();
    
        }
        
        
        // 使用独立线程来打印线程状态
        private static void printState(Thread thread) {
            new Thread(()->{
                while (true){
                    System.out.println(thread.getName()+":"+thread.getState());
                    if (thread.getState().equals(Thread.State.TERMINATED)){
                        System.out.println(thread.getName()+":"+thread.getState());
                        break;
                    }
                }
            }).start();
        }
    }

    执行结果:简化后的输出结果

    Thread-0:NEW
    Thread-1:NEW
    Thread-0:RUNNABLE
    Thread-1:RUNNABLE
    thread0 进入:等待唤醒状态(WAITING)
    Thread-1:BLOCKED
    thread1 进入:计时等待状态(TIMED_WAITING)
    Thread-0:BLOCKED
    Thread-0:WAITING
    ……
    Thread-0:WAITING
    Thread-1:BLOCKED
    Thread-1:TIMED_WAITING
    ……
    Thread-1:TIMED_WAITING
    Thread-1:BLOCKED
    ……
    Thread-1:BLOCKED
    Thread-0:WAITING
    ……
    Thread-0:WAITING
    thread1 出来:计时等待状态(TIMED_WAITING)
    Thread-0:WAITING
    Thread-1:BLOCKED
    thread1 解除:等待唤醒状态(WAITING)
    Thread-1:BLOCKED
    Thread-0:WAITING
    Thread-0:BLOCKED
    thread1 解除完成:等待唤醒状态(WAITING)
    Thread-1:BLOCKED
    thread1 RUNNABLE
    Thread-0:BLOCKED
    Thread-1:TERMINATED
    thread0 被解除完成:等待唤醒状态(WAITING)
    Thread-0:BLOCKED
    thread0 RUNNABLE
    Thread-0:TERMINATED

    Java スレッドの 6 つの状態とライフサイクルとは何ですか?

    最终的执行结果如图。

    注意:因为案例中使用了独立线程来打印不同线程的状态,会出现状态打印稍微延迟的情况。

    以上がJava スレッドの 6 つの状態とライフサイクルとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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