Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

Suppose, that the code that runs as part of your future does not support cooperative cancellation or interruption. Then cancelling an unstarted task is the best thing you can possibly do. That is why this method exists.

In general I think of cancellation as strictly cooperative. Just cancelling some piece of code by force can lead to corrupted state.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top