Dans le code ci-dessous, je signale une exception TimeoutException après 100 secondes, comme prévu. À ce stade, je m’attendrais à ce que le code sorte de main et que le programme se termine, mais l’impression continue sur la console. Comment puis-je arrêter la tâche d’exécution après expiration du délai?
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); private static T timedCall(Callable c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { FutureTask task = new FutureTask(c); THREAD_POOL.execute(task); return task.get(timeout, timeUnit); } public static void main(Ssortingng[] args) { try { int returnCode = timedCall(new Callable() { 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; } }
Vous devez annuler votre tâche à l’expiration du délai (et interrompre son thread). C’est à quoi sert la méthode d’ cancel(true)
. :
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); private static T timedCall(FutureTask task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { THREAD_POOL.execute(task); return task.get(timeout, timeUnit); } public static void main(Ssortingng[] args) { try { FutureTask task = new FutureTask (new Callable () { 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; }
Votre Callable doit être capable de s’arrêter rapidement, au besoin.
Votre code:
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; }
Est déjà capable de le faire grâce à l'appel de Thread.sleep()
. Le fait est que futureTask.cancel(true)
interrompra un autre thread, et votre code doit réagir à cette interruption. Thread.sleep()
fait cela. Si vous n'avez pas utilisé Thread.sleep()
ou un autre code de blocage interruptible, vous devez vérifier Thread.currentThread().isInterrupted()
par vous-même et quitter dès que possible (par exemple en lançant une new InterruptedException()
) lorsque vous trouvez que cela est vrai.
Vous devez appeler futureTask.cancel(true);
de votre gestionnaire d'exceptions pour annuler et interrompre le thread qui exécute votre tâche.
Mon conseil est d’en apprendre davantage sur le mécanisme d’interruption (c’est un excellent article: Traitement de InterruptedException ) et de l’utiliser.
Une fois que vous avez intercepté TimeoutException, vous devez appeler la méthode cancel (true) de votre tâche …
ou arrêtez votre ExecutorService en appelant shutdownNow () …
ou quittez la VM en appelant System.exit (0)
en fonction de vos besoins