Question

I have some experience of using the Java interrupt mechanism to fullfill my work, but currently I am not that clear about when should I set the interrupt status of the current thread and when should I throws InterruptedException?

And, in order to make it more clearer for you, here is the sample that I've previously coded.

This is the code before I start my work:

/*
 * Run a command which locates on a certain remote machine, with the
 * specified timeout in milliseconds.
 * 
 * This method will be invoked by means of
 *     java.util.concurrent.FutureTask
 * which will further submmited to a dedicated
 *     java.util.concurrent.ExecutorService
 */
public void runRemoteSript(String command, long timeout) {
    Process cmd = null;
    try {
        cmd = Runtime.getRuntime().exec(command);

        boolean returnCodeOk = false;
        long endTime = System.currentTimeMillis() + timeout;

        // wait for the command to complete
        while (!returnCodeOk && System.currentTimeMillis() < endTime) {

            // do something with the stdout stream
            // do something with the err stream

            try {
                cmd.exitValue();
                returnCodeOk = true;
            } catch (IllegalThreadStateException e) { // still running
                try {
                    Thread.sleep(200);
                } catch (InterruptedException ie) {
                    // The original code just swallow this exception
                }
            }
        }

    } finall {
        if (null != cmd) {
            cmd.destroy();
        }
    }
}

My intention is to interrupt the command as some of the remote scripts consumes a lot of time before finishing. Thus the runRemoteScript could completed or manually stopped. And here is the updated code:

public void cancel(String cmd) {
    // I record the task that I've previously submitted to
    // the ExecutorService.
    FutureTask task = getTaskByCmd(cmd);

    // This would interrupt the:
    //     Thread.sleep(200);
    // statement in the runRemoteScript method.
    task.cancel(true);
}

public void runRemoteSript(String command, long timeout) {
    Process cmd = null;
    try {
        cmd = Runtime.getRuntime().exec(command);

        boolean returnCodeOk = false;
        long endTime = System.currentTimeMillis() + timeout;

        // wait for the command to complete
        **boolean hasInterruption = false;**
        while (!returnCodeOk && System.currentTimeMillis() < endTime) {

            // do something with the stdout stream
            // do something with the err stream

            try {
                cmd.exitValue();
                returnCodeOk = true;
            } catch (IllegalThreadStateException e) { // still running
                try {
                    Thread.sleep(200);
                } catch (InterruptedException ie) {
                    // The updated code comes here:
                    hasInterruption = true; // The reason why I didn't break the while-loop
                                            // directly is: there would be a file lock on
                                            // the remote machine when it is running, which
                                            // will further keep subsequent running the same
                                            // script. Thus the script will still running
                                            // there.
                }
            }
        }

        // let the running thread of this method have the opportunity to
        // test the interrupt status
        if (hasInterruption) {
            Thread.currentThread().interrupt();
        }

        // Will it be better if I throws a InterruptedException here?

    } finall {
        if (null != cmd) {
            cmd.destroy();
        }
    }
}

The point is, is it better to set the interrupt status for calling thread to test? Or just throws a new InterrutedExeption to the caller? Are there any best practices or particular circumstants in which one of the above approach would fit better?

I would write down my understanding here, so that you could correct my if I missunderstood any of them. According to my understanding, I think the thread.interrupt() is intended for not requiring the client code to handle the interrupt and it's the client code responsibility to decide whether to test it or not, while the throws InterruptedException is a must because it is checked exception?

Was it helpful?

Solution

See this other answer, which links to a very good discussion of interrupts. The main idea is that you should throw the InterruptedException, except where it is impossible. If it's impossible, you should reset the interrupted status by calling Thread.currentThread().interrupt().

Why might it be impossible to rethrow the interrupted exception? You might be calling Thread.sleep() inside the run() method of a class that implements Runnable (which it doesn't look like you are). Because InterruptedException is checked and the run method is not declared to throw any exceptions in the Runnable interface, you cannot rethrow the exception. In that case, it is best to reset the interrupted status, and many containers that use Runnable will handle that properly.

In any case, you're doing the right thing by changing the code so it doesn't swallow the exception.

OTHER TIPS

Interrupting a thread is a mechanism to tell this thread to finish execution as early as possible, abandoning current tasks if possible. Usually this is called to terminate the thread, and your code should honor that properly. This can be done by having a global try/catch block, so that the thread immediately jumps out of any while loop if you have any.

If you use blocking code you can assume that the internal code will eventually throw an InterruptedException at the right moment. If you just have a long calculation, you should check for interruption frequently.

A correct implementation for blocking code should look like this:

public void run() {
  try {
    while (this.running) {
      doSomethingThatBlocks();
    }
  } catch (InterruptedException e) {
    // maybe log if this wasn't expected
  } finally {
    cleanup();
  }
}

The same for non-blocking code, where you have to check interruption yourself, should look like this:

public void run() {
  while (this.isInterrupted() == false) {
    calculation.nextStep();
  }
}

You only need to actually throw an InterruptedException if you are designing a blocking API call. But since almost all Java functions that can potentially block already throw an InterruptedException when necessary, having to throw one yourself is usually an edge case.

If you do have something like a wrapper around an existing API call and need to intercept the interruption for some cleanup, just throw the same interruption once you are done. There is no one hurt by throwing an interruption, it is after all just a signal for termination.

You should back to the basic - what your interrupt for ? when it happen ? and what is expected result ? In normal case, a thread will never being interrupted by other then yourself.

Could you like to cancel the on-going operation? then throw it or return thread. Could you like to consume the interrupted or keep it for callee module?

In most case, you could like to cancel the operation and exit.

When to use thread.interrupt()

Whenever you need to interrupt a thread, which shouldn't be very often.

and when to throws InterruptedException

Only when you need to catch and rethrow it, which should be hardly ever.

Note that you've chosen a very poor example. You should just call Process.waitFor(), and get the exit value if you need it when that returns.

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