Reputation: 1094
I'm trying to find a satisfactory answer for this:
What may cause ScheduledFuture#cancel(false) to return false? Essentially I'm creating a new scheduler like so:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> schedulerStatus = scheduler.scheduleWithFixedDelay(this, 0L, 1L, TimeUnit.SECONDS);
And within the run method I have something like the following:
public void run() {
// Do some logic
schedulerStatus.cancel(false);
}
I've looked at the JavaDoc but it doesn't really say anything helpful,
"or could not be cancelled for some other reason"
So any help in understanding what's exactly happening here would be great!
Thanks
UPDATE
To expand further upon my example above:
private final ScheduledExecutorService scheduler;
private volatile ScheduledFuture<?> schedulerStatus;
@Inject
public IndexChangeManagerImpl(IndexChangeMonitor monitor, IndexChangeObservable observable) {
this.monitor = monitor;
scheduler = Executors.newScheduledThreadPool(1);
}
@Override
public void init() {
if (schedulerStatus == null || schedulerStatus.isDone()) {
// Kick of the scheduler to attempt to initiate the listener every second.
schedulerStatus = scheduler.scheduleWithFixedDelay(this, 0L, 1L, TimeUnit.SECONDS);
}
}
@Override
public void run() {
try {
// Before starting the monitor, ensure it is not currently running.
monitor.shutdown();
// Initiate the monitor.
monitor.start();
// Listener has been established, no more attempts necessary.
schedulerStatus.cancel(false);
lastLog = 0;
} catch (ChangeMonitorException sfE) {
long now = System.currentTimeMillis();
if (lastLog == 0 || now - lastLog > 60000) {
// Log every 60 seconds.
DEBUG.error("Error attempting to initiate index change monitor.", sfE);
lastLog = now;
}
}
}
Hopefully this code snippet demonstrates that the two reasons for cancel returning false are in fact impossible (noting this is all single threaded). As cancel is called within the single scheduled thread clearly the task is neither complete and can't have been cancelled already.
One thing to note is that cancel returning false is intermittent and occurs when the system is under load.
Any further thoughts?
Upvotes: 3
Views: 1465
Reputation: 17329
It looks like it returns false
if it's already done executing or it's already been cancelled.
From the source for the default Future
implementation used by Java's default Executor
implementations:
boolean innerCancel(boolean mayInterruptIfRunning) {
for (;;) {
int s = getState();
if (ranOrCancelled(s))
return false;
if (compareAndSetState(s, CANCELLED))
break;
}
if (mayInterruptIfRunning) {
Thread r = runner;
if (r != null)
r.interrupt();
}
releaseShared(0);
done();
return true;
}
Upvotes: 3