Come faccio ad avere FutureTask per tornare dopo TimeoutException?
-
16-09-2019 - |
Domanda
Nel codice di seguito, sto cattura di un TimeoutException dopo 100 secondi come previsto. A questo punto mi aspetterei il codice per uscire dal principale e il programma per terminare ma mantiene la stampa alla console. Come faccio ad avere il compito di fermare l'esecuzione dopo il timeout?
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;
}
}
Soluzione
È necessario annullare il vostro compito in timeout (e interrupt suo filo). Questo è ciò che il metodo è per 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;
}
Altri suggerimenti
Il mosto richiamabile per essere in grado di fermare rapidamente, in caso di necessità.
Il tuo codice:
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;
}
è già in grado di farlo grazie a chiamare Thread.sleep()
. Punto è che futureTask.cancel(true)
interromperà altro thread, e il codice ha bisogno di reagire a questa interruzione. Thread.sleep()
fa. Se non è stato utilizzato Thread.sleep()
o altro codice interrompibile di blocco, si dovrebbe controllare Thread.currentThread().isInterrupted()
da soli, e uscire il più presto possibile (per esempio lanciando new InterruptedException()
) quando si trova che questo è vero.
È necessario chiamare futureTask.cancel(true);
dal vostro gestore di eccezioni per annullare e interrompere il thread che esegue il compito.
Il mio consiglio è quello di conoscere il meccanismo di interruzione (questo è grande articolo: Trattare con InterruptedException ), e usarlo.
Una volta che hai preso la TimeoutException, è necessario chiamare il metodo cancel (vero) del vostro compito ...
o spegnere l'ExecutorService chiamando shutdownNow () ...
o uscire la VM chiamando System.exit (0)
a seconda delle esigenze