views:

321

answers:

4

I have a long running task, something like:

public void myCancellableTask() {
    while ( someCondition ) {
       checkIfCancelRequested();
       doSomeWork();
    }
 }

The task can be cancelled (a cancel is requested and checkIfCancelRequested() checks the cancel flag). Generally when I write cancellable loops like this, I use a flag to indicate that a cancel has been requested. But, I know I could also use Thread.interrupt and check if the thread has been interrupted. I'm not sure which would be the preferred approach and why, thoughts?

thanks,

Jeff

+3  A: 

Interrupt will blast the thread out of a list of specified wait conditions. Your own cancel flag will not. If you want to interrupt waits on IO and events, use interrupt. Otherwise use your own.

bmargulies
A: 

I think that it's a matter of preference in most cases. Personally I would go for the hand-made flag. It gives you more control - for example, this way you make sure that your thread doesn't leave some other object in an inconsistent state. Besides, if performance is really critical, bear in mind that using exceptions has an overhead (even if it's negligible in 99% of the cases).

Eli Acherkan
A: 

It depends on the doSomeWork() implementation. Is that pure computation or does it (at any point) involve blocking API (such as IO) calls? Per bmargulies's answer, many blocking APIs in JDK are interruptible and will propagate the interrupted exception up the stack.

So, if the work entails potentially blocking activities, you need'll to take interrupts into consideration even if you decide to control the process using a flag, and should appropriately catch and handle/propagate the interrupts.

Beyond that, if relying on a flag, make sure your flag is declared with volatile semantics.

+6  A: 

One problem with using interrupt is that if you do not control all code being executed, you run the risk of the interrupt not working "properly" because of someone else's broken understanding of how to handle interrupts in their library. That is the API invisibly exports an API around its handling of interrupts which you become dependent on.

In your example, suppose doSomeWork was in a 3rd-party JAR and looks like:

public void doSomeWork() {
    try { 
        api.callAndWaitAnswer() ; 
    } 
    catch (InterruptedException e) { throw new AssertionError(); }
}

Now you have to handle an AssertionError (or whatever else the library you are using might throw). I've seen experienced developers throw all sorts of nonsense on receiving interrupts! On the other hand, maybe the method looked like this:

public void doSomeWork() {
    while (true) {
        try { 
            return api.callAndWaitAnswer() ; 
        } 
        catch (InterruptedException e) { /* retry! */ }
    }
}

This "improper handling" of interrupt causes your program to loop indefinitely. Again, don't dismiss this as ridiculous; there are a lot of broken interrupt handling mechanisms out there.

At least using your own flag will be completely invisible to any 3rd-party libraries.

oxbow_lakes
Good stuff here. It's all too common to see the swallowing of the interrupt or just logging and continuing without resetting the interrupt flag. I think people get frustrated that it's a checked exception they don't know what to do with, so they don't do anything at all.
Jeff Storey