同じスレッドでstartメソッドを2回呼び出すことは合法ですか?


89

次のコードは、プログラムで2回目にメソッドjava.lang.IllegalThreadStateException: Thread already startedを呼び出したときに表示されます。start()

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

これは2目にupdateUI.start()呼び出されたときに発生します。私はそれを何度も実行しましたが、スレッドが呼び出され、ヒットする前に完全に実行されupdateUI.start()ます。

呼び出しupdateUI.run()はエラーを回避しますが、スレッドをUIスレッド(SOの他の投稿で述べた呼び出しスレッド)で実行させますが、これは私が望むものではありません。

スレッド一度だけ開始できますか?もしそうなら、もう一度スレッドを実行したい場合はどうすればよいですか?この特定のスレッドは、UIスレッドで実行されるよりもスレッドで実行されず、ユーザーが不当に長い待機をしている場合、バックグラウンドでいくつかの計算を実行しています。


9
なぜjavadocを読んだだけではなかったのですか-それは契約を明確に説明しています。
mP。

回答:


111

以下からのJavaのAPI仕様のためのThread.start方法:

スレッドを複数回開始することは決して合法ではありません。特に、スレッドは実行が完了すると再起動されない場合があります。

さらに:

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

したがって、はい、Thread開始できるのは1回だけです。

もしそうなら、もう一度スレッドを実行したい場合はどうすればよいですか?

Thread複数回実行する必要がある場合は、の新しいインスタンスを作成しThreadて呼び出す必要がありますstart


ありがとう。私はIDEのドキュメントとスレッドのJavaチュートリアル(そしてGoogleも)をチェックしました。将来、API仕様を確認する予定です。その重要な「..二度以上開始することは決して合法ではない..」は他の読み物にはありません。
ウィル

@coobird、古いスレッドオブジェクト名を新しいThread()に割り当てた場合、古いスレッドが終了した後、古いスレッドはガベージコレクションされますか(つまり、自動的にリサイクルされますか、または明示的に実行する必要があります)?
snapfractalpop 2012

スレッドが実行されていない限り、ガベージコレクションされます。
2013

1
この答えは少し時代遅れです。最新のJavaプログラムでタスクを複数回実行する必要がある場合は、Thread毎回新しいプログラムを作成しないでください。代わりに、タスクをスレッドプールに送信する必要があります(例:java.util.concurrent.ThreadPoolExecutor
Solomon Slow

13

その通りです。 ドキュメントから

スレッドを複数回開始することは決して合法ではありません。特に、スレッドは実行が完了すると再起動されない場合があります。

繰り返し計算に対して何ができるかという点では、SwingUtilitiesのinvokeLaterメソッドを使用できるように見えます。あなたはすでにrun()直接呼び出しを実験しています。つまりRunnable、rawではなくを使用することをすでに考えていますThread。タスクinvokeLaterだけでメソッドを使用してみて、Runnableそれがあなたのメンタルパターンに少しよく合うかどうかを確認してください。

ドキュメントの例は次のとおりです。

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

そのprintln呼び出しをあなたの計算に置き換えれば、それはまさにあなたが必要とするものであるかもしれません。

編集:コメントをフォローアップしましたが、元の投稿のAndroidタグに気付きませんでした。AndroidでのinvokeLaterに相当するのはHandler.post(Runnable)です。そのjavadocから:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

したがって、Androidの世界では、上記と同じ例を使用して、Swingutilities.invokeLaterをへの適切な投稿に置き換えることができますHandler


OPは、SwingUtilitiesを含まないAndroidでのスレッド化について質問しています。
オースティンマホニー

@オースティン、あなたは正しい。Handler.post()に関する注釈を追加して、Androidの並列コードを説明しました。
Bob Cross

1
UIを更新するだけの場合の別の方法は、独自のハンドラーを使用するRunOnUIThread(Runnable)View.post(Runnable)作成することです。これらはメインスレッドでランナブルを実行し、UIを更新できるようにします。
オースティンマホニー

3

到着したばかりの答えは、あなたがしていることをしてはいけない理由をカバーしています。ここにあなたの実際の問題を解決するためのいくつかのオプションがあります。

この特定のスレッドは、UIスレッドで行われるよりもスレッドで行わない場合、ユーザーが不当に長い待機をしている場合、バックグラウンドでいくつかの計算を実行しています。

独自のスレッドをダンプして使用しますAsyncTask

または、必要なときに新しいスレッドを作成します。

または、スレッドをLinkedBlockingQueue再起動するのではなく、ワークキュー(例:)から操作するようにスレッドを設定します。


3

いいえ、Threadを再度開始することはできません。そうすると、runtimeException java.lang.IllegalThreadStateExceptionがスローされます。>

その理由は、run()メソッドがスレッドによって実行されると、デッド状態になるためです。

例を挙げましょう。スレッドを再び開始し、そのスレッドでstart()メソッドを呼び出す(内部ではrun()メソッドを呼び出す)と考えると、死んだ人に目を覚まして実行するように要求するようなものです。彼の人生を終えた後、人は死んだ状態になります。

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
    }

}

/ * run()メソッドのOUTPUT、メソッドが完了しました。スレッド「メイン」での例外java.lang.Thread.start(Unknown Source)でのjava.lang.IllegalThreadStateException * /

これをチェックして


2

実行する必要があるのは、Runnableを作成し、Runnableを実行するたびに新しいスレッドでラップすることです。それは本当に醜いでしょうが、別のスレッドでスレッドをラップして、そのコードを再度実行することができますが、これを実行する必要があるのは、本当にそうする必要がある場合のみです。


スニペット、ラップする方法は?
Vinay 2017年

1

あなたが言ったように、スレッドは複数回開始することはできません。

馬の口から直接Java API仕様

スレッドを複数回開始することは決して合法ではありません。特に、スレッドは実行が完了すると再起動されない場合があります。

スレッドで起こっていることをすべて再実行する必要がある場合は、新しいスレッドを作成して実行する必要があります。


0

スレッドを再利用することは、Java APIでは不正なアクションです。ただし、それを実行可能な実装にラップして、そのインスタンスを再実行することもできます。


0

はい、すでに実行中のスレッドを開始することはできません。実行時にIllegalThreadStateExceptionがスローされます-スレッドが既に開始されている場合。

本当にスレッドを開始する必要がある場合:オプション1)スレッドを複数回実行する必要がある場合は、スレッドの新しいインスタンスを作成し、そのインスタンスでstartを呼び出す必要があります。


0

スレッドは一度だけ開始できますか?

はい。正確に1回だけ開始できます。

もしそうなら、スレッドをもう一度実行したい場合はどうすればよいですか?この特定のスレッドは、UIスレッドで実行したよりもスレッドで実行しておらず、ユーザーが不当に持っている場合、バックグラウンドでいくつかの計算を実行しています長い待ち時間。

Thread再度実行しないでください。代わりに、作成したRunnableをしてに投稿ハンドラHandlerThread。複数のRunnableオブジェクトを送信できます。Runnable run()メソッド内でUIスレッドにデータを送り返す場合 MessageHandler、UIスレッドのオンとポストを投稿しますhandleMessage

コード例については、この投稿を参照してください。

Android:スレッドでトースト


0

良い方法かどうかはわかりませんが、run()メソッドの内部でrun()を呼び出せば、エラーは発生せず、実際に必要な処理を実行できます。

スレッドが再び開始されるわけではないことはわかっていますが、多分これが役に立つでしょう。

public void run() {

    LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();

    try {
        NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
        Thread.sleep(5000);
        if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
            System.out.println("{There was a NetworkState change!}");
            run();
        } else {
            run();
        }
    } catch (SocketException | InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
    checkingNetworkStates.start();
}

これがほんの少しでも役立つことを願っています。

乾杯


-1

それは本当に醜いでしょうが、別のスレッドでスレッドをラップして、そのコードを再度実行することができますが、これを実行する必要があるのは、本当にそうする必要がある場合のみです。

スレッドを作成したプログラマが引き起こしたリソースリークを修正する必要がありましたが、スレッドを開始()する代わりに、run()メソッドを直接呼び出しました。したがって、それが引き起こす副作用を本当に理解していない限り、それを避けてください。


しかし、提案はrun()直接呼び出すのではなく、単にRunnableをスレッドに埋め込み、おそらくを呼び出すことstart()でした。
H2ONaCl 2011

@ H2ONaCl私が引用したテキストを読んだ場合、提案はスレッドをスレッドにラップすることでした。編集する前に、元の提案を読むことができなかった可能性があります。
Torben
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.