Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would you use both a boolean AND interrupt() to signal thread termination?

I was reading about ways to end a thread in https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html, which is a link I found from the question How do you kill a thread in Java?

In the first link, they first discuss using a volatile variable to signal to the thread that you want to terminate. The thread is supposed to check this variable and cease operation if the variable has a value that means cease (e.g. if it is null). So to terminate the thread, you would set that variable to null.

Then they discuss adding interrupts to help with threads that block for long periods of time. They give the following example of a stop() method that sets the volatile variable (waiter) to null and then ALSO throws an interrupt.

public void stop() {
    Thread moribund = waiter;
    waiter = null;
    moribund.interrupt();
}

I am just wondering, why would you need both? Why not ONLY use interrupt(), and then handle it properly? It seems redundant to me.

like image 377
Stephen Avatar asked Mar 28 '18 15:03

Stephen


Video Answer


2 Answers

Please see this documentation. Your thread should check thread.isInterrupted() status, for example:

Thread myThread = new Thread()  {
    @Override
    public void run() {
        while (!this.isInterrupted()) {
            System.out.println("I'm working");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //We would like also exit from the thread
                return;
            }
        }
    }
};

And when you would like to stop the thread, you should invoke

myThread.interrupt();

Besides we can use static method Thread.interrupted() that also checks the status but after that, the method clears it and you have to invoke again myThread.interrupt() to set the status again. But I don't recommend to use Thread.interrupted() method.

This approach helps gracefully stop the thread.

So I also do not see any reasons to use an additional volatile variable.

The same behavior can be reached via additional volatile flag as in @lexicore's answer, but I think it is redundant code.

like image 38
statut Avatar answered Sep 22 '22 14:09

statut


(First part of this is in general, arguably I was not paying attention to the specifics of the question. Skip to the end for the part that addresses the techspec discussed in the question.)

There is no good technical reason. This is partly about human limitations and partly about confusing api design.

First consider application developers’ priority is creating working code that solves business problems. Thoroughly learning low level apis like this gets lost in the rush to get work done.

Second there’s a tendency when you’re learning things to get to a good enough state and leave it there. Things like threading and exception handling are back-of-the-book topics that get neglected. Interruption is a back of the book topic for threading books.

Now imagine a codebase worked on by multiple people with varying skill level and attention to detail, who may forget that throwing InterruptedException from wait and sleep resets the interrupt flag, or that interrupted isn’t the same as isInterrupted, or that InterruptedIoException resets the interrupt flag too. If you have a finally block that catches IOException, you may miss that InterruptedException is a subclass of IOException and you could be missing out on restoring the interrupt flag. Probably people in a hurry decided to hell with it, I can’t count on this interrupted flag

Is it right? No.

  • The hand rolled flag doesn’t help with short circuiting wait or sleep the way interruption does.

  • the Java 5 concurrency tools expect tasks to use interruption for cancellation. Executors expect tasks submitted to them to check for interruption in order to quit gracefully. Your tasks may use other components, like a blocking queue. That queue needs to be able to respond to interruption, the thing using it needs to be aware of the interruption. The handrolled flag doesn’t work for this since the java 5 classes can’t know about it.

Having to use interruption because you’re using tools that expect it, but not having confidence in the flag value due to unmanageable technicalities, would lead to this kind of code.

(end of rant, now actually responding to the specific techspec example)

OK, looking at this techguide article in particular. Three things stand out:

1) it's not making use of interruption at all, except to cut the sleep time short. Then it just squelches the exception, and doesn't bother to restore the flag or check it. You could use the InterruptedException to terminate by catching it outside the while loop, but that's not what this does. This seems like a strange way to do this.

2) as the example is fleshed out it becomes clear the flag is being used to turn the waiting on and off. Somebody might use interruption for this but it's not idiomatic. So having a flag is ok here.

3) this is a toy example in a techguide. Not all the Oracle content is as authoritative as the techspecs or the API documentation. Some tutorials have misstatements or are incomplete. It might be the reason the code was written like this was that the author figured readers would not be familiar with how interruption worked and it was better to minimize its usage. Technical writers have been known to make choices like that.

If I rewrote this to use interruption I would still keep the flag; I'd use interrupt to terminate, and use the flag for suspend/resume functionality.

like image 73
Nathan Hughes Avatar answered Sep 23 '22 14:09

Nathan Hughes