9

以下のコードでは、意図したとおり、100秒後にTimeoutExceptionが発生しています。この時点で、コードがmainから終了し、プログラムが終了することを期待しますが、コンソールへの出力は続行されます。タイムアウト後にタスクの実行を停止するにはどうすればよいですか?

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
    FutureTask<T> task = new FutureTask<T>(c);
    THREAD_POOL.execute(task);
    return task.get(timeout, timeUnit);
}


public static void main(String[] args) {

    try {
        int returnCode = timedCall(new Callable<Integer>() {
            public Integer call() throws Exception {
                for (int i=0; i < 1000000; i++) {
                    System.out.println(new java.util.Date());
                    Thread.sleep(1000);
                }
                return 0;
            }
        }, 100, TimeUnit.SECONDS);
    } catch (Exception e) {
        e.printStackTrace();
        return;
    }


}
4

3 に答える 3

11

タイムアウト時にタスクをキャンセルする(そしてそのスレッドを中断する)必要があります。それがそのcancel(true)方法です。:

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

private static <T> T timedCall(FutureTask<T> task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
    THREAD_POOL.execute(task);
    return task.get(timeout, timeUnit);
}


public static void main(String[] args) {
        try {
            FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
                public Integer call() throws Exception {
                        for (int i=0; i < 1000000; i++) {
                                if (Thread.interrupted()) return 1;
                                System.out.println(new java.util.Date());
                                Thread.sleep(1000);
                        }
                        return 0;
                }
            });
            int returnCode = timedCall(task, 100, TimeUnit.SECONDS);
        } catch (Exception e) {
                e.printStackTrace();
                task.cancel(true);
        }
        return;
}
于 2009-08-15T05:59:10.537 に答える
4

Callableは、必要に応じてすばやく停止できる必要があります。

あなたのコード:

public Integer call() throws Exception {
    for (int i=0; i < 1000000 && !task.cancelled(); i++) {
        System.out.println(new java.util.Date());
        Thread.sleep(1000); // throws InterruptedException when thread is interrupted
    }
    return 0;
}

を呼び出すことで、すでにそれを行うことができThread.sleep()ます。ポイントは、futureTask.cancel(true)他のスレッドを中断することであり、コードはこの中断に反応する必要があります。Thread.sleep()それをします。Thread.sleep()または他の割り込み可能なブロッキングコードを使用しなかった場合は、自分で確認し、これが当てはまることがわかったらThread.currentThread().isInterrupted()、できるだけ早く(たとえば、スローして)終了する必要があります。new InterruptedException()

futureTask.cancel(true);タスクを実行するスレッドをキャンセルして中断するには、例外ハンドラーから呼び出す必要があります。

私のアドバイスは、割り込みメカニズム(これは素晴らしい記事です:InterruptedExceptionの処理)について学び、それを使用することです。

于 2009-08-15T06:30:32.110 に答える
2

TimeoutExceptionをキャッチしたら、タスクのcancel(true)メソッドを呼び出す必要があります...

または、shutdownNow()を呼び出してExecutorServiceをシャットダウンします。

または、System.exit(0)を呼び出してVMを終了します

あなたのニーズに応じて

于 2009-08-15T05:51:57.070 に答える