Javaスレッドの問題の概要

1. Javaスレッドのライフサイクル:

 

 

 

 

糸の5つの状態 

1.新しい状態(新規):スレッドオブジェクトのペアが作成されると、次のような新しい状態になります。Thread t = new MyThread();

2.準備完了状態(実行可能):スレッドオブジェクトのstart()メソッド(t.start();)が呼び出されると、スレッドは準備完了状態になります。準備完了状態のスレッドは、CPU を使用する権利を取得するために、CPUがいつでも実行をスケジュールするのを待っている準備ができていることを意味します。これは、t.start()の実行直後にスレッドが実行されることを意味しません

3.実行状態(実行中):実行可能状態のスレッドは、CPUタイムスライス(タイムスライス)を取得し、プログラムコードを実行します。CPUがスレッドを準備完了状態でスケジュールすることを開始すると、スレッドは実際に実行できます。つまり、スレッドは実行状態になります。注:作動可能状態への唯一のエントリーは、作動可能状態です。つまり、スレッドが実行のために作動状態に入ろうとする場合、最初に作動可能状態でなければなりません。

4.ブロック:実行状態のスレッドは、何らかの理由で一時的にCPUを使用する権利を放棄します。つまり、CPUタイムスライスを放棄し、実行を停止し、準備ができるまでブロック状態に入ります。状態、それは実行状態に入るためにCPUによって再び呼び出される機会があります。再度CPUタイムスライスを取得して実行状態に移行する機会がある場合のみブロッキングのさまざまな原因に応じて、ブロッキング状態は次の3つのタイプに分類できます。

  1. ブロッキングを待機中:実行状態のスレッドはwait()メソッドを実行して、スレッドを待機ブロッキング状態にします; JVMはスレッドを待機キュー(待機キュー)に入れます
  2. 同期ブロッキング:実行中のスレッドがオブジェクトの同期ロックを取得すると、同期ロックが別のスレッドによって占有されており、同期同期ロックの取得に失敗すると、同期ブロッキング状態になり、JVMがスレッドをロックプールに入れます。 (ロックプール)
  3. その他のブロッキング:スレッドのsleep()またはjoin()を呼び出すか、I / O要求を発行すると、スレッドはブロッキング状態に入ります。sleep()状態がタイムアウトになると、join()はスレッドの終了またはタイムアウトを待機するか、I / O処理が完了すると、スレッドは再び準備完了状態になります。実行中のスレッドがThread.sleep(long ms)またはt.join()メソッドを実行するか、I / O要求を発行すると、JVMはスレッドをブロック状態にします。sleep()状態がタイムアウトするか、join()がスレッドの終了またはタイムアウトを待機するか、I / O処理が完了すると、スレッドは再び実行可能状態になります

5.デッドステート(Dead):スレッドが例外のために実行を終了するか、run()メソッドを終了すると、スレッドはそのライフサイクルを終了します。


2、睡眠、降伏、参加、待機总结

  • sleep:ロックリソースを解放せずにCPUリソースを解放します。Threadクラスのメソッドは、timeパラメーターをとる必要があります。現在のスレッドをスリープ状態にしてCPUを解放し、優先度を考慮せずに他のスレッドを実行する機会を提供しますが、同期ロックがある場合、スリープはロックを解放しません。つまり、他のスレッドはinterrupt()メソッドを呼び出して同期ロックを取得できません。スリープ状態のスレッドを起こします。
  • 収量:CPUスケジューリングあきらめるユーザーが一時停止する期間を指定することができないことを除いて、睡眠に似Threadクラスのメソッド、、 および歩留まり()メソッドは、同じ優先順位のスレッドが実行する機会を持つことができるようにすることができます。Yield()は、現在のスレッドを実行可能状態に戻すだけなので、yield()を実行するスレッドは、実行可能状態に入っ直後実行される可能性あります。yieldメソッドの呼び出しは、私の作業がほぼ完了し、同じ優先度の他のスレッドがCPUを使用できるようにスレッドスケジューラに通知するための提案にすぎません。採用を保証するメカニズムはありません。
  • wait:CPUリソースを解放し、ロックリソースも解放します。Objectクラスのメソッド(notify()、notifyAll()もObjectオブジェクトです)は、ループ本体と同期コードブロックに配置する必要があります。メソッドを実行するスレッドはロックを解放し、スレッドが待機しているプールに入り、再び目覚めるのを待ちます(通知はランダムに起きます) 、NotifyAllウェイクアップすると、スレッドはスレッドの終了後に自動的にウェイクアップし、それをロックプールに入れて同期ロックを獲得します。
  • join:特別な種類の待機であるスレッドクラスメソッド。現在実行中のスレッドは別のスレッドのjoinメソッドを呼び出し、現在のスレッドは、別のスレッドが終了してスレッドが終了するまで待機するまでブロッキング状態になります。このメソッドも例外をキャッチする必要があることに注意してください。続行する前に、joinメソッドを呼び出したスレッドが終了するのを待ちます。例:t.join();は、主にtスレッドの終了を待機するために使用されます。そのような文がない場合、mainが実行され、予期しない結果になります。
join() 一直等待
join(long millis) 等待指定毫秒数
join(long millis, int nanos) 等待指定毫秒数

 


3.割り込みの概要

バックグラウンド:

  1. Javaでは、スレッドをすぐに停止する方法はありません(Thread.stop()メソッドは廃止としてマークされているため、stopメソッドは失礼すぎてスレッドを停止できず、スレッドをすぐに停止できます。また、リソースの解放などの後続の操作のための余地を残さず、安全が確保されます。隠れた危険)。
  2. たとえば、あるスレッド内の別のスレッドの状態を制御したい場合:時間のかかる操作をキャンセルします。現時点では、Javaの割り込みメカニズムを使用できます。

割り込みとは:

  • 割り込みは単なる協調メカニズムであり、Javaは割り込みに構文を追加しません。割り込みプロセスは、プログラマーが完全に実装する必要があります。スレッドを中断するには、スレッドの中断されたメソッドを手動で呼び出す必要があります。このメソッドは、スレッドオブジェクトの中断フラグをtrueに設定するだけです。次に、現在のスレッドのフラグビットを継続的にチェックする独自のコードを記述する必要があります。trueの場合、別のスレッドがこのスレッドへの割り込みを必要としていることを示します。この時点で実行する必要があることを実装するコードを作成する必要があります。
  • 各スレッドオブジェクトには、スレッドが中断されているかどうかを示すフラグがあり、フラグビットは中断を示す場合はtrue、中断されていない場合はfalseです。
  • スレッドオブジェクトのinterruptメソッドを呼び出して、スレッドのフラグをtrueに設定します。他のスレッドまたは独自のスレッドで呼び出すことができます。

関連する中断方法:

public void interrupt() 将调用者线程的中断状态设为true。
public boolean isInterrupted() 判断调用者线程的中断状态。
public static boolean interrupted 只能通过Thread.interrupted()调用。 它会做两步操作:
返回当前线程的中断状态;将当前线程的中断状态设为false;

割り込み方法の使用:

/**
 * @Description 测试不同状态下线程被中断后的行为
 * @Author lhy
 * @Date 2019/11/21 15:01
 */
public class TheadStatusInterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        testRunningInterrupt();
        testBlockedInterrupt();
    }

    /**
     * 测试阻塞状态下被interrupt
     * @throws InterruptedException
     */
    private static void testBlockedInterrupt() throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.currentThread().sleep(5000);
                    } catch (InterruptedException e) {
                        System.out.println("catch:" + Thread.currentThread().isInterrupted());
                        break;
                    }
                }
                //经过catch InterruptedException 处理后的线程中断状态已经被重置
                System.out.println("interrupted!!!:" + Thread.currentThread().isInterrupted());
            }
        });
        t1.start();
        Thread.currentThread().sleep(2000);
        t1.interrupt();
        t1.join();
    }

    /**
     * 测试运行中状态的线程被interrupt
     * @throws InterruptedException
     */
    private static void testRunningInterrupt() throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("running...");
                }
                //中断处理的代码
                System.out.println("interrupted!!!" + Thread.currentThread().isInterrupted());
            }
        });
        t1.start();
        Thread.currentThread().sleep(2000);
        t1.interrupt();
        t1.join();
    }
}

 

    /**
     * 测试运行中状态的线程被interrupt
     * @throws InterruptedException
     */
    private static void testRunningAfterBlockedInterrupt() throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    System.out.println("running...:"+i++);
                    if(i>5000){
                        try {
                            System.out.println("sleep:" +     
                            Thread.currentThread().isInterrupted());
                            //阻塞之前,interrupt被设置为true,此次会抛出异常
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            //catch中 interrupt状态位已经被自动重置为false
                            System.out.println("interrupted!!!" + 
                            Thread.currentThread().isInterrupted());
                            break;
                        }
                    }
                }
            }
        });
        t1.start();
        t1.interrupt();
        t1.join();
    }

総括する:

  • interruptメソッドは、割り込みステータスをtureに設定するだけで、割り込みスレッドがブロックされると、この時点で例外がスローされ、割り込みステータスはfalseになります。
  • interruptedメソッドは、2つの処理を実行し、現在の中断状態を返し、中断状態をクリアします。falseをtrueに戻すことはできませんが、trueをfalseにクリアすることしかできません。
     

    interrupt()メソッドを本当に理解するには、最初にstop()メソッドを理解する必要があります。以前は、thread.stop()によってスレッドを停止できました。stop()メソッドは、あるスレッドが別のスレッドを停止するために使用できることに注意してください。このメソッドは暴力的で安全ではありません。スレッドAがスレッドBを呼び出すと言う方法stopメソッドは、スレッドBを停止するために使用されます。このメソッドが呼び出されると、スレッドAは実際にはスレッドBの特定の実行を認識しません。この突然の停止により、スレッドBのクリーンアップ作業が完了できなくなり、stopを実行する別の状況があります。スレッドBは、メソッドの直後にロックを解放します。これにより、データの同期外れの問題が発生する可能性があります。上記の問題に基づいて、stop()メソッドは廃止されました。
この場合、interrupt()メソッドが表示されます。stopとは異なります。これはスレッドを実際に停止するのではなく、スレッドにシグナルを送信して、スレッドが終了することを通知する(停止フラグを設定する)だけです。本当に安全なアプローチは、あるスレッドが別のスレッドを終了させるのではなく、スレッド自体を終了させることです。

    interrupt()メソッドと.interrupted()メソッドの連携により、スレッドを正常に停止できます。スレッドAは、スレッドBの割り込みメソッドを呼び出すことにより、スレッドBにスレッドの終了を通知します。スレッドBのrunメソッド内で、ループチェックが渡されます。スレッドAのシグナルを受信するために.interrupted()メソッドがtrueであるかどうか。trueの場合、例外がスローされ、catchでクリーンアップ作業が行われた後、スレッドが終了します。Thread.interrupted()はフラグビットをクリアします。これは、スレッドが再開したことを意味するものではありません。割り込みシグナルに応答し、シグナルを再度受信できる状態にリセットしただけであると理解できます。最初から最後まで、重要なポイントを理解してください。interrupt()メソッドはフラグビットの値を変更するだけであり、必ずしもスレッドの状態とは関係ありません。

 

 

 

おすすめ

転載: blog.csdn.net/qq_36807862/article/details/105988368