15

呼び出したいメソッドがあります。ただし、実行に時間がかかりすぎる場合は、それを強制終了するか、強制的に戻すためのクリーンで簡単な方法を探しています。

私はJavaを使用しています。

説明する:

logger.info("sequentially executing all batches...");
for (TestExecutor executor : builder.getExecutors()) {
logger.info("executing batch...");
executor.execute();
}

TestExecutorクラスはimplement Callableその方向に進むべきだと思います。

しかし、私ができることは、executor.execute()時間がかかりすぎる場合は停止することだけです.

提案...?

編集

寄せられた提案の多くは、実行中のメソッドに時間がかかり、何らかのループが含まれており、変数が定期的にチェックされる可能性があることを前提としています。しかし、そうではありません。したがって、必ずしもクリーンであるとは限らず、どこにいても実行を停止するだけのものは許容されます。

4

7 に答える 7

11

次のクラスを確認する必要があります: FutureTaskCallableExecutors

次に例を示します。

public class TimeoutExample {
    public static Object myMethod() {
        // does your thing and taking a long time to execute
        return someResult;
    }

    public static void main(final String[] args) {
        Callable<Object> callable = new Callable<Object>() {
            public Object call() throws Exception {
                return myMethod();
            }
        };
        ExecutorService executorService = Executors.newCachedThreadPool();

        Future<Object> task = executorService.submit(callable);
        try {
            // ok, wait for 30 seconds max
            Object result = task.get(30, TimeUnit.SECONDS);
            System.out.println("Finished with result: " + result);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            System.out.println("timeout...");
        } catch (InterruptedException e) {
            System.out.println("interrupted");
        }
    }
}
于 2008-10-27T22:03:36.033 に答える
8

Javaの中断メカニズムは、この種のシナリオを対象としています。中止したいメソッドがループを実行している場合は、反復ごとにスレッドの中断ステータスをチェックするように指示します。中断された場合は、InterruptedExceptionをスローします。

次に、中止する場合は、適切なスレッドで割り込みを呼び出す必要があります。

または、非推奨の停止方法の代わりに、Sunが提案するアプローチを使用することもできます。これには例外のスローは含まれず、メソッドは通常どおりに戻ります。

于 2008-10-27T15:56:54.137 に答える
7

I'm assuming the use of multiple threads in the following statements.

I've done some reading in this area and most authors say that it's a bad idea to kill another thread.

If the function that you want to kill can be designed to periodically check a variable or synchronization primitive, and then terminate cleanly if that variable or synchronization primitive is set, that would be pretty clean. Then some sort of monitor thread can sleep for a number of milliseconds and then set the variable or synchronization primitive.

于 2008-10-27T15:40:03.187 に答える
3

本当にできません...それを行う唯一の方法は、thread.stopを使用するか、「協調的」メソッドに同意することです(たとえば、Thread.isInterruptedをときどきチェックするか、InterruptedExceptionをスローするメソッド(たとえば、Thread)を呼び出すことです。 sleep())、またはどういうわけか別のJVMでメソッドを完全に呼び出します。

特定の種類のテストでは、stop()を呼び出しても問題ありませんが、テストスイートの状態が損なわれる可能性があるため、相互作用の影響を回避する場合は、stop()を呼び出すたびにJVMを再起動する必要があります。

協調的アプローチを実装する方法の適切な説明については、非推奨のThreadメソッドに関するSunのFAQを確認してください。

実生活でのこのアプローチの例として、 EclipseRCPのJobAPI「IProgressMonitor」オブジェクトを使用すると、一部の管理サービスがサブプロセスに(「cancel」メソッドを介して)停止するように通知できます。もちろん、それは実際にisCancelledメソッドを定期的にチェックするメソッドに依存していますが、これはしばしば失敗します。

ハイブリッドアプローチは、スレッドに割り込みを適切に要求し、数秒後に停止を要求することです。繰り返しになりますが、本番コードではstopを使用しないでください。ただし、この場合は特に問題ない可能性があります。すぐにJVMを終了した場合。

このアプローチをテストするために、実行可能なものを取得して実行しようとする単純なハーネスを作成しました。コメント/編集してください。

public void testStop(Runnable r) {
    Thread t = new Thread(r);
    t.start();
    try {
        t.join(2000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }

    if (!t.isAlive()) {
        System.err.println("Finished on time.");
        return;
    }

    try {
        t.interrupt();
        t.join(2000);
        if (!t.isAlive()) {
            System.err.println("cooperative stop");
            return;
        }
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.err.println("non-cooperative stop");
    StackTraceElement[] trace = Thread.getAllStackTraces().get(t);
    if (null != trace) {
        Throwable temp = new Throwable();
        temp.setStackTrace(trace);
        temp.printStackTrace();
    }
    t.stop();
    System.err.println("stopped non-cooperative thread");
}

それをテストするために、2つの競合する無限ループを作成しました。1つは協調ループで、もう1つはスレッドの中断されたビットをチェックしません。

public void cooperative() {
    try {
        for (;;) {
            Thread.sleep(500);
        }
    } catch (InterruptedException e) {
        System.err.println("cooperative() interrupted");
    } finally {
        System.err.println("cooperative() finally");
    }
}

public void noncooperative() {
    try {
        for (;;) {
            Thread.yield();
        }
    } finally {
        System.err.println("noncooperative() finally");
    }
}

最後に、テスト(JUnit 4)を作成して、それらを実行しました。

@Test
public void testStopCooperative() {
    testStop(new Runnable() {
        @Override
        public void run() {
            cooperative();
        }
    });
}

@Test
public void testStopNoncooperative() {
    testStop(new Runnable() {
        @Override
        public void run() {
            noncooperative();
        }
    });
}

私はこれまでThread.stop()を使用したことがなかったので、その操作に気づいていませんでした。これは、ターゲットスレッドが現在実行されている場所からThreadDeathオブジェクトをスローすることで機能します。これはエラーを拡張します。したがって、常に正常に機能するとは限りませんが、通常は、かなり妥当なプログラム状態の単純なプログラムが残ります。たとえば、finallyブロックが呼び出されます。本当のジャークになりたいのなら、とにかくThreadDeath(またはError)をキャッチして、実行を続けることができます!

他に何もないとしても、これは本当にIProgressMonitorアプローチに従ったコードをもっと望んでいます-時間がかかる可能性のあるメソッドに別のパラメーターを追加し、メソッドの実装者に、ユーザーがシステムに与えることを望んでいるかどうかを確認するためにモニターオブジェクトを時々ポーリングするように促します上。将来的には、特にインタラクティブな方法で、このパターンに従うようにします。もちろん、どの方法がこのように使用されるかを事前に知っている必要はありませんが、それがプロファイラーの目的だと思います。

「別のJVMを完全に開始する」メソッドについては、さらに作業が必要になります。誰かが委任クラスローダーを作成したかどうか、または1つがJVMに含まれているかどうかはわかりませんが、このアプローチにはそれが必要です。

于 2008-10-27T15:54:53.610 に答える
1

誰も直接答えなかったので、これが私が少量の疑似コードであなたに与えることができる最も近いものです:

メソッドをrunnable/callableでラップします。メソッド自体は、停止したい場合は割り込みステータスをチェックする必要があります(たとえば、このメソッドがループの場合は、ループ内でThread.currentThread()。isInterruptedをチェックし、そうであれば、ループを停止します(donただし、すべての反復をチェックしないでください。そうしないと、処理が遅くなります。ラッピングメソッドで、thread.join(timeout)を使用して、メソッドを実行する時間を待つか、ループ内でjoinを呼び出します。待機中に他のことを行う必要がある場合は、タイムアウトを短くして繰り返します。メソッドが終了しない場合は、参加後、上記の推奨事項を使用して高速/クリーンを中止します。

したがって、コードに関しては、古いコード:

void myMethod()
{
    methodTakingAllTheTime();
}

新しいコード:

void myMethod()
{
    Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                 methodTakingAllTheTime(); // modify the internals of this method to check for interruption
            }
        });
    t.join(5000); // 5 seconds
    t.interrupt();
}

ただし、これを正常に機能させるには、methodTakingAllTheTimeを変更する必要があります。そうしないと、割り込みを呼び出した後もそのスレッドが実行を継続します。

于 2008-10-27T17:16:00.437 に答える
0

これを行うにはそれほど素晴らしい方法ではないと思います。時間がかかりすぎていることを検出できる場合は、すべてのステップでメソッドにブール値をチェックさせることができます。時間がかかりすぎる場合は、プログラムで boolean の tooMuchTime の値を true に変更します (これについてはお手伝いできません)。次に、次のようなものを使用します。

 Method(){
 //task1
if (tooMuchTime == true) return;
 //task2
if (tooMuchTime == true) return;
 //task3
if (tooMuchTime == true) return;
//task4
if (tooMuchTime == true) return;
//task5
if (tooMuchTime == true) return;
//final task
  }
于 2014-05-06T11:41:25.847 に答える