TimeoutException の後に FutureTask を返すようにするにはどうすればよいですか?
-
16-09-2019 - |
質問
以下のコードでは、意図どおり 100 秒後に TimeoutException をキャッチしています。この時点で、コードがメインから終了し、プログラムが終了することが期待されますが、コンソールに出力され続けます。タイムアウト後にタスクの実行を停止するにはどうすればよいですか?
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;
}
}
解決
あなたはタイムアウトであなたのタスクをキャンセル(およびそのスレッドを中断)する必要があります。それは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;
}
他のヒント
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 への対処)を使用してください。
あなたはTimeoutExceptionを捕まえたら、あなたのタスクのキャンセル(true)メソッドを呼び出す必要があります...
またはshutdownNowの()を呼び出すことによって、あなたのExecutorServiceのをシャットダウン...
またはにSystem.exitを呼び出してVMを終了(0)
あなたのニーズに応じて、