4

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?

Vic Lau
  • 173
  • 2
  • 8

4 Answers4

7

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.

Community
  • 1
  • 1
Denise
  • 1,947
  • 2
  • 17
  • 29
  • :) Thanks for your clear explanation about the situtations of using InterrutedException and Thread.currentThread().interrupt(). I think I understand the basic principle now: in general, do not swallow the InterruptedException, the right way is to rethrough the exception if is possible. If not possible, set the interrupt status so that any one who care about that can take action on it. A further question: As the InterruptedException is a checked exception, it might bother the caller's logic sequence. So I was wondering I could use the t.interrupt() if I want to simplify the caller's sequence? – Vic Lau Nov 13 '13 at 05:29
  • You're right, that's another aspect to consider. Throwing the exception will force the calling thread to handle the exception. Theoretically, that's what the interrupter "expects", ie, that you will handle the interruption immediately and shut down. However because of existing code you could choose to handle it the other way and explicitly check each thread to see if it's been interrupted. – Denise Nov 13 '13 at 05:44
  • ps. Welcome to the site! When you see answers you like, you should upvote/accept ;-) – Denise Nov 13 '13 at 05:51
  • Ok, I accepted your answer just now. And sorry for cannot upvote your answer for I have only 6 points of reputation. :( – Vic Lau Nov 13 '13 at 05:53
  • np, very interesting question! – Denise Nov 13 '13 at 12:25
1

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.

TwoThe
  • 13,879
  • 6
  • 30
  • 54
0

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.

Dennis C
  • 24,511
  • 12
  • 71
  • 99
  • The runRemoteScript will be called several tiems during a FutureTask. Each invocation send a piece of data to the script on a remote machine, the script has a file lock when it is running, and if I just break or return from the on-going operation, the file lock is still on the machine because the script is still running. In that way, subsequent runs of the same script will have no effect because of the existed file lock, so I need to record the interruption in a boolean field, and set the interrupt status after this round of running the script. – Vic Lau Nov 13 '13 at 05:40
  • (...continued) And before the next round of running the same script with differenct script data, I could check whether a interruption has happened. If yes, I could cancel sending the rest data to the remote script. In fact, I will only interrupt those scripts who might spent a long period of time to complete, and let followed scripts to run. – Vic Lau Nov 13 '13 at 05:44
  • If you want to wait it complete forever, just wait forever. Why time it out? Because you might want to cancel it, or catching error. You really should cancel a script gracefully, or log error and block retry unless your file being unlocked – Dennis C Nov 13 '13 at 05:53
  • Yes, you are right. The process for canceling a script here is not quite graceful. But my situation is the remote script is not maintained by our team, and sometimes they even don't work. In fact, this is not a timeout issue, it is not working scripts issue. This is only a approach for us to manually stop those very slowly script or broken script. – Vic Lau Nov 13 '13 at 06:04
0

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I think your word does not help with a general principle, and it is still confused for me to decide when to use either approach. According to your answer, either approach can help with indicating there is a interruption issued. But really thanks for suggesting me the Process.waitFor() to look up the return code and wait the completion. Thanks! – Vic Lau Nov 13 '13 at 05:20