Wenn ein Befehl mit fester Rate an einem beliebigen ScheduledExecutorService geplant wird, wird ScheduledFuture zurückgegeben, die ebenfalls abgebrochen werden kann. Aber "Abbrechen" bietet keine Garantie dafür, dass der Befehl nach Abbruch der Rückgabe nicht ausgeführt wird, z. B. weil der Befehl bereits in der Mitte der Ausführung war, als "cancell" aufgerufen wurde.So stornieren Sie ShceduledFuture und warten Sie, bis Runnable beendet wird, wenn zum Zeitpunkt der Stornierung Runnable ausgeführt wird?
Für die meisten Anwendungsfälle reicht die Funktionalität aus. Aber ich habe mich mit Usecase beschäftigt, wenn der aktuelle Thread nach dem Abbrechen blockiert werden muss, wenn der Befehl bereits ausgeführt wird, und warten bis der Befehl erledigt ist. Mit anderen Worten, Thread, der cancel aufgerufen hat, sollte nicht vorwärts gehen, wenn der Befehl noch ausgeführt wird. Abbrechen mit mayInterruptIfRunning = true ist auch nicht geeignet, da ich die aktuellen Ausführungen nicht unterbrechen will, muss ich nur auf normales abschließen warten.
Ich habe nicht gefunden, wie man diese Anforderungen über Standard-JDK-Klassen erreicht. Frage1: War ich falsch und diese Art von Funktionalität existiert?
Also beschloss ich, es selbst zu implementieren: import java.util.concurrent. *;
public class GracefullyStoppingScheduledFutureDecorator implements ScheduledFuture {
/**
* @return the scheduled future with method special implementation of "cancel" method,
* which in additional to standard implementation,
* provides strongly guarantee that command is not in the middle of progress when "cancel" returns
*/
public static ScheduledFuture schedule(Runnable command, long initialDelay, long period, TimeUnit unit, ScheduledExecutorService scheduler) {
CancellableCommand cancellableCommand = new CancellableCommand(command);
ScheduledFuture future = scheduler.scheduleAtFixedRate(cancellableCommand, initialDelay, period, unit);
return new GracefullyStoppingScheduledFutureDecorator(future, cancellableCommand);
}
private GracefullyStoppingScheduledFutureDecorator(ScheduledFuture targetFuture, CancellableCommand command) {
this.targetFuture = targetFuture;
this.runnable = command;
}
private final ScheduledFuture targetFuture;
private final CancellableCommand runnable;
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
runnable.cancel();
return targetFuture.cancel(mayInterruptIfRunning);
}
@Override
public long getDelay(TimeUnit unit) {
return targetFuture.getDelay(unit);
}
@Override
public int compareTo(Delayed o) {
return targetFuture.compareTo(o);
}
@Override
public boolean isCancelled() {
return targetFuture.isCancelled();
}
@Override
public boolean isDone() {
return targetFuture.isDone();
}
@Override
public Object get() throws InterruptedException, ExecutionException {
return targetFuture.get();
}
@Override
public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return targetFuture.get(timeout, unit);
}
private static class CancellableCommand implements Runnable {
private final Object monitor = new Object();
private final Runnable target;
private boolean cancelled = false;
private CancellableCommand(Runnable target) {
this.target = target;
}
public void cancel() {
synchronized (monitor) {
cancelled = true;
}
}
@Override
public void run() {
synchronized (monitor) {
if (!cancelled) {
target.run();
}
}
}
}
}
Question2: jeder Fehler im Code oben finden kann?