The general answer to your question can be found on How to remove a task from ScheduledExecutorService?
However to answer your specific question, "how can I do it from within the task?" - it's slightly trickier. You want to avoid the (unlikely) race condition where your task completes before the scheduleAtFixedRate
method completes and makes the reference to the ScheduledFuture
available to be stored in a field.
The below code solves this by using a CompletableFuture
to store the reference to the ScheduledFuture
that represents the task.
public class CancelScheduled {
private ScheduledExecutorService scheduledExecutorService;
private CompletableFuture<ScheduledFuture<?>> taskFuture;
public CancelScheduled() {
scheduledExecutorService = Executors.newScheduledThreadPool(2);
((ScheduledThreadPoolExecutor) scheduledExecutorService).setRemoveOnCancelPolicy(true);
}
public void run() {
taskFuture = new CompletableFuture<>();
ScheduledFuture<?> task = scheduledExecutorService.scheduleAtFixedRate(
() -> {
// Get the result of the REST call (stubbed with "SUCCESS" below)
String result = "SUCCESS";
if (result.equals("SUCCESS")) {
// Get the reference to my own `ScheduledFuture` in a race-condition free way
ScheduledFuture<?> me;
try {
me = taskFuture.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
me.cancel(false);
}
}, 0, 30, TimeUnit.SECONDS);
// Supply the reference to the `ScheduledFuture` object to the task itself in a race-condition free way
taskFuture.complete(task);
}