Utility of Future.cancel(boolean) method

41,886

Solution 1

How does wrapping a Callable in a FutureTask help if the Thread can't be stopped by cancel?

You want to cancel the task, not the thread running it. Using cancel(true) prevents the task from starting (but doesn't remove it from the queue) and interrupts the thread if the task has started. The Task can ignore the interrupt, but there is no clean way of killing a thread without killing the whole process.

Solution 2

The problem that you are overlooking is that only cooperating threads can be stopped safely in Java.

Indeed, if you look at the Thread API, you will notice that there are some methods called destroy, pause, stop, and resume that were deprecated in Java 1.1. The reason that they were deprecated is that the Java designers realized that they generally can't be used safely. The reasons are explained in the note "Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?".

The problem is inherent in the Java threading model, and could only be avoided by curtailing the ability of one thread to interact with objects used by other threads. There is a JSR that specifies one one way of doing this ... Isolates ... but no mainstream JVMs implement these APIs to my knowledge.


So bringing this back to your question, the usefulness of Future.cancel is that it solves the subset of the problem that can be solved in the context of futures.

Solution 3

Invoking cancel(true) will prevent the Future from executing if not already run and will be interrupted if currently running. At this point, the burden to cancel the Future is put on the developer.

Since it is a thread pool it wouldn't make sense to stop the thread (though it rarely if ever makes sense to stop a thread). The cancel/interrupt will not cause the thread to exit from its run method. After the execution of your Callable's call method it will simply pull the next item off the work queue and process that.

The utility of the cancel method is simply to signal the executing thread that some process want's that Callable to stop - not the thread - so you will have to handle the stopping of the Callable yourself.

Share:
41,886

Related videos on Youtube

Kaliyug Antagonist
Author by

Kaliyug Antagonist

I am a simple guy who believes knowledge can never be the destination - it's an eternal journey !

Updated on July 09, 2022

Comments

  • Kaliyug Antagonist
    Kaliyug Antagonist almost 2 years

    I was simply exploring the java.util.concurrent package.

    I learnt that the class 'Future' has a method boolean cancel(boolean mayInterruptIfRunning)

    Please find attached the test code I wrote :

    package com.java.util.concurrent;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.ScheduledFuture;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    
    public class FutureTester {
    
    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        int poolCnt = 1;
        Callable<NumberPrinter> numberPrinter = null;
        ScheduledThreadPoolExecutor schPool = new ScheduledThreadPoolExecutor(
                poolCnt);
        ScheduledFuture<NumberPrinter>[] numPrinterFutures = new ScheduledFuture[poolCnt];
        FutureTask<NumberPrinter>[] futureTask = new FutureTask[poolCnt];
    
        for (int i = 0; i < poolCnt; i++) {
            numberPrinter = new NumberPrinter();
            futureTask[i] = new FutureTask<NumberPrinter>(numberPrinter);
    
            /*
             * numPrinterFutures[i] = (ScheduledFuture<NumberPrinter>) schPool
             * .schedule(futureTask[i], 0, TimeUnit.MILLISECONDS);
             */
            numPrinterFutures[i] = (ScheduledFuture<NumberPrinter>) schPool
                    .submit(futureTask[i]);
        }
    
        //Thread.sleep(30);
    
        if (numPrinterFutures.length > 0) {
    
            System.out.println("Task completed ? "
                    + numPrinterFutures[0].isDone());
    
            System.out.println("Task cancelled ? "
                    + numPrinterFutures[0].cancel(true));
    
            System.out.println("Is task cancelled ? "
                    + numPrinterFutures[0].isCancelled());
        }
    }
    
    }
    
    class NumberPrinter implements Callable<NumberPrinter> {
    
    private int counter = 10;
    
    @Override
    public NumberPrinter call() throws Exception {
        // TODO Auto-generated method stub
    
        while (counter > 0) {
            if (Thread.interrupted()) {/*OUCH !!!*/
                return null;
            }
            System.out.println("counter = " + (counter--));
        }
    
        return this;
    }
    
    }
    

    Intially,I assumed that cancelling a task will also stop the execution of a running thread(the 'OUCH' part NOT included).But I got the output as follows :

    counter = 10
    Task completed ? false
    counter = 9
    Task cancelled ? true
    counter = 8
    Is task cancelled ? true
    counter = 7
    counter = 6
    counter = 5
    counter = 4
    counter = 3
    counter = 2
    counter = 1
    

    On further reading on stackoverflow itself,it was said that

    1. The 'cancel' method can only stop the 'unstarted' jobs(which contradicts with the api description of the method)
    2. The cancel method simply interrupts the running thread which then must return from the run() method

    Hence,I included the 'OUCH' part - a while loop checking for interruption;the output was as follows :

    Task completed ? false
    counter = 10
    Task cancelled ? true
    Is task cancelled ? true
    

    QUESTION :

    If one is supposed to write something analogous to the 'OUCH' part to stop the running thread,what is the utility/value of the cancel method. How does wrapping a Callable in a FutureTask help if the Thread can't be stopped by cancel? What is the design/conceptual/logical part that I am overlooking?

    • voidMainReturn
      voidMainReturn over 10 years
      I faced the same problem. I didn't know why my thread pools are getting exhausted at a certain point. Now I figured why. Thanks.
  • Anuradhe Dilshan
    Anuradhe Dilshan almost 4 years
    It was Realy Helpul than Other answers :)