What does Future.cancel() do if not interrupting?
Asked Answered
I

3

26

From java docs on Future.cancel()

boolean cancel(boolean mayInterruptIfRunning)

Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

My question is what does cancel do if mayInterruptIfRunning is false?
how does it cancel or stop the task from executing if it has already been run?

Iain answered 29/1, 2014 at 23:51 Comment(0)
F
19

If it is not interrupting it will simply tell the future that is is cancelled. You can check that via isCancelled() but nothing happens if you don't check that manually.

Below example code shows how you could do it.

private static FutureTask<String> task = new FutureTask<String>(new Callable<String>() {

    @Override
    public String call() throws Exception {
        while (!task.isCancelled()) {
            System.out.println("Running...");
            Thread.sleep(1000);
        }
        return "The End";
    }

});

public static void main(String[] args) throws InterruptedException {
    new Thread(task).start();
    Thread.sleep(1500);
    task.cancel(false);
}

The task is started, and after 1.5 iterations told to stop. It will continue sleeping (which it would not if you interrupted it) and then finish.

Freed answered 29/1, 2014 at 23:56 Comment(9)
but i can't "know" that from within the object?? (Future<SomeObject>)Iain
Note that there would be no way of checking isCancelled() from e.g. Callable.call - it could only check if it was interrupted.Pedo
@PaulBellora see updated answer. You need to add some way to reference the Future from within the Callable to make that work.Freed
@Freed Okay but that seems a little weird and self-defeating. while (!Thread.interrupted()) { would make more sense.Pedo
Yes, I typically do that and say task.cancel(true) because that's accessible via Thread.interrupted(). With false you will never get Thread.interrupted() return true because it does not interrupt. I have not found much use for cancel(false) or a pattern how you don't have to use ugly references to the outside either :)Freed
@Freed Right, it seems like cancel(false) would be for preventing it from starting, but if you didn't want to interrupt it otherwise.Pedo
It's probably much more useful for that since it is really tricky to come up with a nice way to be able to check it otherwise. You could potentially want that your thread is not interrupted though and just ended once you decide to do so. pastebin.com/1QPvVVkF is already a tad nicer but still not great.Freed
Eclipse 4.6 doesn't let you do this. The expression !task.isCancelled() gives the un-ignoreable error "The local variable task may not have been initialized". Since task has to be final or effectively final, you're stuck.Shastashastra
@LukeHutchison works fine for me. task is not a local variable, it's a field of the enclosing class.Freed
B
6

nothing will be done if the task has already started and mayInterruptIfRunning is false,

below is the cancel()

public boolean cancel(boolean mayInterruptIfRunning) {
    if (state != NEW)
        return false;
    if (mayInterruptIfRunning) {
        if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))
            return false;
        Thread t = runner;
        if (t != null)
            t.interrupt();
        UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state
    }
    else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))
        return false;
    finishCompletion();
    return true;
}

we can see that if mayInterruptIfRunning is false,cancel() just change state from NEW to CANCELLED and return false,nothing else will be done

Brittbritta answered 7/6, 2017 at 15:19 Comment(0)
P
3

My question is what does cancel do if mayInterruptIfRunning is false? how does it cancel or stop the task from executing if it has already been run?

If the task has already started running, and mayInterruptIfRunning is false, then there is nothing to be done. In Java, interrupting a thread is considered to be the only safe way of stopping it short of completion - and even that requires the task to "comply" by checking for interruption at some implementation-specific interval.

Related: How do you kill a thread in Java?

Pedo answered 29/1, 2014 at 23:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.