11

次のコードを使用すると例外がIllegalThreadStateException発生します:このスレッドを(を使用してthread.start())一度開始し、別の場所で再度開始しようとしたため、次のコードを使用しました:

thread.interrupt();
thread.start();

しかしthread.start()、投げてIllegalThreadStateExceptionいます。

それを解決するには何を使うべきですか?

4

2 に答える 2

18

Threadオブジェクトは1回だけ開始することを目的としています。を停止/中断する必要がありThread、それを再開したい場合は、新しいインスタンスを作成して、それを呼び出す必要がありますstart()

thread.interrupt();  // if you need to make sure thread's run() method stops ASAP
thread = new MyThreadSubclass();
thread.start();

APIドキュメントから

IllegalThreadStateException-スレッドがすでに開始されている場合。

start()以前に電話をかけたとしても、もう一度電話をかけられないことは100%明確ではありませんがinterrupt()、それが機能する方法です。

標準JavaのAPIドキュメントを見ると、この問題はより明確です。

于 2012-11-24T05:59:13.197 に答える
8

ネイトの答えに加えて。

AnkitRox はコメントで次のように述べています。

ありがとうネイト。私もあなたの方法を試していました。しかし、そのときに発生した問題は、新しいインスタンスの新しいスレッドを開始し、前のスレッドも機能していたことです。

つまり、問題は「割り込みを呼び出してもスレッドがまだ実行されている」ことのようです。次のサンプルを検討してください (見苦しいですが、主なアイデアを示すには十分です):

final Thread t = new Thread(new Runnable() {
    public void run() {
        while (true) {
            for (int i = 0; i < 100000000; i++); // simulate some action
            System.out.println("hi, interrupted = " 
                    + Thread.currentThread().isInterrupted());
        }
    }
});
t.start();
new Timer(true).schedule(
    new TimerTask() {
        public void run() {
            t.interrupt();
        }
    },
    1000 // 1 second delay
);

interrupt()が呼び出された後も、スレッドは引き続き実行されることに注意してください。生成される出力は次のとおりです。

hi, interrupted = false
hi, interrupted = true
hi, interrupted = true
hi, interrupted = true
...
hi, interrupted = true

実際には、強制的に閉じない限り、プログラムは停止しません。それで、 は何をinterrupt()しますか?中断フラグを に設定するだけtrueです。interrupt()が呼び出された後、Thread.currentThread().isInterrupted()が戻り始めfalseます。それだけです。

別のケースとしてinterrupt()、 をスローするメソッドのいずれかの呼び出しでスレッドがブロックされている間に が呼び出された場合、そのメソッドは をスローしInterruptedExceptionて戻りInterruptedExceptionます。そして、スレッドのコードがその例外を「食べる」だけの場合、スレッドは引き続き実行されます。サンプルを検討してください。

final Thread t = new Thread(new Runnable() {
    public void run() {
        while (true) {
            System.out.println("hi, interrupted = " 
                    + Thread.currentThread().isInterrupted());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("got InterruptedException");
            }
        }
    }
});
t.start();
new Timer(true).schedule(
    new TimerTask() {
        public void run() {
            t.interrupt();
        }
    },
    1000 // 1 second delay
);

interrupt()が呼び出された後も、スレッドは引き続き実行されることに注意してください。生成される出力は次のとおりです。

hi, interrupted = false
got InterruptedException
hi, interrupted = false
hi, interrupted = false
...
hi, interrupted = false

今回は が呼び出されたinterrupted = false後でも注意してください。interrupt()これは、InterruptedExceptionがキャッチされるたびに、中断フラグが にリセットされるためfalseです。

Java では、スレッドの停止は協調メカニズムです。つまり、スレッド自体の協力なしにはできないということです。上記のサンプルの修正版は次のとおりです。

final Thread t = new Thread(new Runnable() {
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("hi, interrupted = " 
                    + Thread.currentThread().isInterrupted());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("we've been interrupted");
                // restore the interrupted flag
                Thread.currentThread().interrupt();
            }
        }
    }
});
t.start();
new Timer(true).schedule(
    new TimerTask() {
        public void run() {
            t.interrupt();
        }
    },
    1000 // 1 second delay
);

したがって、正しいアプローチは、中断されたフラグを定期的にチェックすることです。中断されたステータスが検出された場合は、できるだけ早く戻ります。別の一般的なオプションは、まったく使用Thread.interrupt()しないことですが、代わりにいくつかのカスタムブール値を使用します。

于 2012-11-25T14:47:59.757 に答える