1. ホーム

[解決済み】スレッドをタイムアウトさせる方法

2022-04-02 16:47:45

質問

あるスレッドをある一定時間実行したい。その時間内に完了しなかった場合、そのスレッドを殺すか、例外を投げるか、何らかの方法で処理したい。どのようにすればよいのでしょうか?

からわかった1つの方法です。 このスレッド は、Threadのrun()メソッド内でTimerTaskを使用することです。

何か良い解決策はないでしょうか?



EDIT: より明確な回答が必要だったため、懸賞金を追加します。以下のExecutorServiceのコードは、私の問題を解決していません。なぜ私は(いくつかのコード - 私はこのコードの部分に対するハンドルを持っていない)実行した後にsleep()する必要がありますか?コードが完了し、sleep()が中断された場合、それはどのようにtimeOutになることができますか?

実行する必要のあるタスクは、私のコントロール下にありません。どのようなコードでもかまいません。問題は、このコード片が無限ループに陥る可能性があることです。私はそうなって欲しくありません。だから、そのタスクは別のスレッドで実行したい。親スレッドはそのスレッドが終了するまで待たなければならず、タスクの状態(タイムアウトしたのか、例外が発生したのか、成功したのか)を知る必要がある。タスクが無限ループに入ると、親スレッドは無限に待ち続けることになり、これは理想的な状況ではありません。

解決方法は?

確かに ExecutorService の代わりに Timer では、ここで エスシーシーイー :

package com.stackoverflow.q2275443;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            future.cancel(true);
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
        return "Ready!";
    }
}

で少し遊んでみてください。 timeout の引数は Future#get() メソッドで、例えば 5 に増やすと、スレッドが終了することがわかります。のタイムアウトを傍受することができます。 catch (TimeoutException e) ブロックを作成します。

更新しました。 は、概念的な誤解を解くために sleep() ではなく が必要です。SSCCE/デモンストレーションのために使用されるだけです。ただ あなたの の代わりに、その場で長く続くタスク sleep() . 長い実行タスクの内部では、スレッドが次のようなものでないかをチェックする必要があります。 割り込み を次のようにします。

while (!Thread.interrupted()) {
    // Do your long running task here.
}