JUCマルチスレッド:スレッドの割り込み停止

        スレッドの停止は、通常手動で停止するのではなく、スレッドが自然に終了するのを待ちますが、実際の開発では、例外など、事前に手動でスレッドを停止する必要があります。プログラムエラーの場合、ユーザーはプログラムを閉じます。糸をうまく止められない場合、様々な問題が発生する可能性がありますので、正しく糸を止めることが非常に重要です。糸を切る一般的な方法は次のとおりです。

1.メソッド1:Threadクラスのstop()メソッドを使用して、スレッドを終了します。

        Threadクラスのstop()メソッドはスレッドを終了できますが、このメソッドは放棄されたメソッドとしてマークされています。その理由は、stop()メソッドが暴力的すぎるためです。スレッドが半分しか実行されていなくても、強制的に終了し、スレッドリソースの正しい解放を保証できません。これはスレッドセーフではなく、予測できない結果をもたらすため、使用することはお勧めしません。

2.方法2:volatileによって変更されたフラグに従って、スレッドを中断する必要があるかどうかを判断します。

    public static class ChangeObjectThread extends Thread 
    {
		// 表示是否停止线程
		private volatile boolean stopMe = true;
		public void stopMe() {
			stopMe = false;
		}
 
		@Override
		public void run() {
			while (!stopMe) {
                System.out.println("I'm running");
			}
		}
	}

        上記のコードでは、スレッドを終了する必要があるかどうかを識別するためにマーカー変数stopMeが定義されています。stopMe()メソッドが呼び出されると、stopMeはfalseに割り当てられます。このとき、コードのwhile(!stopMe)は変更が検出され、スレッドが終了します

3.方法3:割り込み割り込みメカニズムを介してスレッドを終了します。

        このメソッドのコアは、interrupt()メソッドを介してスレッドの割り込みフラグビットを設定し、isInterrupt()/interrupted()メソッドを介して割り込みシグナルを監視および判断することです。スレッドがそれが真であることを検出すると、割り込み信号を受信したことを意味します。割り込みスレッドは対応する処理を行います。しかし、割り込み信号にどのように応答するか、割り込みスレッドは完全な自律性を持っています。つまり、割り込み結果は、割り込みスレッド自体のロジックに応じて、終了するか、実行を継続します。

  • Thread.interrupte():スレッドの割り込みフラグをtrueに設定して、他のスレッドによって割り込みが行われたことを示しますが、stop()メソッドのように実行中のスレッドの割り込みを強制することはなく、停止したスレッドに通知するだけです。 ;そして、中断されたスレッドは、isInterrupted()またはinterrupted()メソッドを使用して中断されているかどうかを判断するなど、自身のフラグが中断されているかどうかを監視することによって応答する必要があります。
  • this.interrupted():現在のスレッドが中断されているかどうかをテストします。このメソッドが2回続けて呼び出された場合、1回目はtrueを返し、2回目はfalseを返します。これは、interrupted()メソッドに状態をクリアする機能があるため、その内部実装は現在のスレッドのisInterrupted()です。が呼び出され、現在のスレッドは割り込みステータスにリセットされます。
  • this.isInterrupted():スレッドが中断されたかどうかをテストしますが、ステータスフラグをクリアしません

        前述のように、割り込みメカニズムは、割り込みフラグが変更されて処理されたかどうかを監視するためにスレッドによって中断される必要があります。次に、スレッドがブロック状態にある場合、正確には、スレッドはObject.wait(によってブロックされます。 )、Thread.join()およびThread.sleep()3つのメソッドのいずれかがブロックされた場合はどうすればよいですか?実際、interrupt()メソッドはスレッドのブロックもサポートしています。上記の場合にスレッドの割り込みステータスが「interrupted」に設定されると、割り込み例外InterruptedExceptionがスローされ、ブロックされた状態が早期に終了するため、すべてあなたがする必要があるのは、InterruptedExceptionをキャッチし、割り込みに応答することです。ただし、InterruptedExceptionをスローする前に、JVMはスレッドの割り込みフラグをリセットするため、この時点でisInterrupted()メソッドを呼び出すとfalseが返されますが、スレッドがブロックもパスもされていない場合は、isInterrupted()/ isInterrupted()を監視してそれに応じて動作します、interrupt()を呼び出しても、現時点では効果がありません。以下に、2つのinterrupt()メカニズムの2つの例を示します。

3.1。interrupt()+ isInterrupted()を使用して、スレッドを中断します。

 public static void main(String[] args)
    {
        //创建 interrupt-1 线程
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println(Thread.currentThread().getName() + "线程正在执行...");
                if (Thread.currentThread().isInterrupted())
                {
                    System.out.println("线程1 接收到中断信息,中断线程...中断标记:" + Thread.currentThread().isInterrupted());
                    Thread.currentThread().interrupted(); 
                    System.out.println("经过 Thread.interrupted() 复位后,中断标记:" + Thread.currentThread().isInterrupted());
                    break;
                }
            }
        }, "interrupt-1");
        //启动线程 1
        thread.start();

        //创建 interrupt-2 线程,用于设置线程1的中断状态
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("设置线程中断...." );
            thread.interrupt();

        },"interrupt-2").start();
    }

3.2.interrupt()+ InterruptedExceptionを使用して、スレッドを中断します。

    public static void main(String[] args)
    {
        //创建 interrupt-1 线程
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println(Thread.currentThread().getName() + "线程1开始执行...");
                //判断当前线程是否中断,
                if (Thread.currentThread().isInterrupted())
                {
                    System.out.println("线程1 接收到中断信息,中断线程...中断标记:" + Thread.currentThread().isInterrupted());
                    break;
                }

                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //因为抛出InterruptedException异常后,会导致中断标志复位为false,所以再次设置线程的中断状态,也可以直接使用break中断线程
                    Thread.currentThread().interrupt();
                    //break;
                }
            }
            System.out.println("线程1执行结果...");
        }, "interrupt-1");
        //启动线程 1
        thread.start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("设置线程中断...." );
        //用于设置线程1的中断状态
        thread.interrupt();
    }

        上記の実行結果から、スレッドがブロック状態の場合、割り込み通知を感知して例外をスローすることもできるため、長時間のスリープ中にスレッドが中断を感じないことを心配する必要がないことが証明できます。 。

        スレッドを停止する最も正確で洗練された方法は、interrupt()を使用することですが、interrupt()は、停止したスレッドに通知するためだけに機能します。停止したスレッドの場合、完全な自律性があります。すぐに停止でき、一定期間後に停止することを選択できます。時間の、または停止しないことを選択します。たとえば、InterruptedExceptionをスローした後、設定を再度中断して、プログラムが操作を終了し続けることができるようにします。たとえば、スレッドがファイルの書き込みなどのIO操作を実行しているとき、スレッドを終了する信号を受信したとき、すぐには停止しませんが、ファイル全体を正常に書き込んだ後に停止するかどうかは、通知されたスレッドの処理によって異なります。スレッドをすぐに終了すると、データが不完全になる可能性があり、ビジネス上望ましくない結果ではないためです。 。そうすると、多くの読者は、この場合の存在の意味は何であるか疑問に思うかもしれません。実際、Javaの場合、プログラムは相互に通知して連携できる管理スレッドであることが期待されているためです。

参考記事:

https://www.cnblogs.com/myseries/p/10918819.html

https://www.cnblogs.com/i-code/p/13804624.html

おすすめ

転載: blog.csdn.net/a745233700/article/details/122641839