Ho esteso FutureTask
da java.util.concurrent
per fornire richiamate per tenere traccia dell'esecuzione di attività inoltrate a ExecutorService
.Estensione di FutureTask, come gestire cancel
public class StatusTask<V> extends FutureTask<V> {
private final ITaskStatusHandler<V> statusHandler;
public StatusTask(Callable<V> callable, ITaskStatusHandler<V> statusHandler){
super(callable);
if (statusHandler == null)
throw new NullPointerException("statusHandler cannot be null");
this.statusHandler = statusHandler;
statusHandler.TaskCreated(this);
}
@Override
public void run() {
statusHandler.TaskRunning(this);
super.run();
}
@Override
protected void done() {
super.done();
statusHandler.TaskCompleted(this);
}
}
Ora, quello che vedo è se il compito è presentata, ma finisce in coda e ho cancel(true);
il compito - il metodo run()
viene ancora chiamata - e la FutureTask.run()
(probabile) controlla che il compito viene annullato e doesn chiamiamo il callable avvolto.
Devo fare ad es.
@Override
public void run() {
if(!isCancelled()) {
statusHandler.TaskRunning(this);
super.run();
}
}
Oppure devo chiamare ancora super.run()
? Entrambi questi approcci sembrano suscettibili alle condizioni di gara tra il controllo dell'annullamento e il fare qualcosa al riguardo. Ogni pensiero è apprezzato.
Presumo che la chiamata nella clausola finally debba essere statusHandler.TaskCompleted (this); C'è qualche caso in cui il metodo run non sarebbe chiamato ma il metodo done() sarebbe? – nos
Grazie per aver colto l'errore. Ho risolto la chiamata nel blocco finally. Sì, è possibile che done() possa essere chiamato senza essere eseguito(). Vedi FutureTask # SynC# innerCancel (booleano). Lì, a condizione che l'attività non abbia finito di funzionare, il che include che non ha mai iniziato a funzionare, puoi vedere che done() sarà chiamato. Nota che done() sarà chiamato zero o una volta per qualsiasi istanza FutureTask: zero se né run() né cancel() non vengono mai chiamati, una volta altrimenti. – seh
Sembra però che se lo si invia a un executor done() verrà chiamato se l'attività viene annullata prima dell'esecuzione, anche se l'executor non lo sa. L'executor conosce solo i runnables/callables. Quindi, run() verrà chiamato quando alla fine diventa eseguibile in quel caso FutureTask # run() essenzialmente non fa nulla però. – nos