Ich habe FutureTask
von java.util.concurrent
erweitert, um Callbacks bereitzustellen, um die Ausführung von Aufgaben zu verfolgen, die an eine ExecutorService
übergeben werden.Erweitern von FutureTask, wie mit cancel umgehen
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);
}
}
Nun, was ich sehe, ist, wenn die Aufgabe gestellt, aber am Ende der Warteschlange und i cancel(true);
die Aufgabe - die run()
Methode wird noch genannt - und die FutureTask.run()
(wahrscheinlich) prüft, ob die Aufgabe abgebrochen und doesn nenne nicht das umhüllte Callable.
Sollte ich z.B.
@Override
public void run() {
if(!isCancelled()) {
statusHandler.TaskRunning(this);
super.run();
}
}
Oder soll ich noch anrufen super.run()
? Beide Ansätze scheinen anfällig zu sein für Race Conditions zwischen dem Überprüfen der Annullierung und dem Tun von etwas darüber.
Ich nehme an, der Aufruf in der finally-Klausel sollte statusHandler.TaskCompleted sein (this); Gibt es einen Fall, in dem die Methode run nicht aufgerufen würde, aber die Methode done()? – nos
Danke für den Fehler. Ich habe den Anruf im finally-Block behoben. Ja, es ist möglich, dass done() aufgerufen werden kann, ohne dass run() aufgerufen wurde. Siehe FutureTask # SynC# innerCancel (boolesch). Dort, vorausgesetzt, dass die Aufgabe nicht beendet wurde, was beinhaltet, dass sie nie gestartet wurde, können Sie sehen, dass done() aufgerufen wird. Beachten Sie, dass done() für jede FutureTask-Instanz null oder einmal aufgerufen wird: null, wenn weder run() noch cancel() einmal aufgerufen werden. – seh
Scheint jedoch, wenn Sie es an einen Executor übergeben done() wird aufgerufen, wenn die Aufgabe abgebrochen wird, bevor es ausgeführt wird - obwohl der Executor nicht darüber weiß. Der Executor kennt nur Runnables/Callables. So wird run() aufgerufen, wenn es schließlich runnable wird in diesem Fall FutureTask # run() tut im Wesentlichen nichts. – nos