2

I was playing around with following example:

public static void interrupted() throws InterruptedException {
    Runnable task = () -> {
        while(true && !Thread.currentThread().isInterrupted()) {
            System.out.println("task executing");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    
    Thread thread = new Thread(task);
    
    thread.start();
    //lets allow spawned thread to run by sleeping main thread for 10 seconds 
    Thread.currentThread().sleep(10000);
    thread.interrupt();
}

when I run this method I was expecting :

1 that the task started via Runnable would run a few times and print SOP

2 above would be possible since main thread sleeps for 10 seconds

3 once main thread wakes up it calls interrupt on the spawned thread

4 in the Runnable task we are checking for isInterrupted so this should get triggered and spawned thread should exit thereby allowing the JVM to exit.

However this is not happening and eclipse / jvm shows that the spawned thread is still running the while loop

Here is the console :

task executing
task executing
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at basics.StopEx.lambda$1(StopEx.java:39)
at java.lang.Thread.run(Thread.java:748)
task executing
task executing
task executing
task executing
........

The java docs regarding interrupt do seem to indicate that calling 'sleep' would cause a different behavior ( highlighted below ) - can someone throw some light on what is exactly happening here and why ?

Interrupts this thread.

Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a java.nio.channels.ClosedByInterruptException.

If this thread is blocked in a java.nio.channels.Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Interrupting a thread that is not alive need not have any effect.

Community
  • 1
  • 1
akila
  • 667
  • 2
  • 7
  • 21
  • my bad regarding the name of the method I used - it could as well have been 'xyz' or this entire code could be invoked in the main method . so No - the name of the method has nothing to do with it though admittedly its a bad choice – akila Jun 28 '19 at 00:50
  • See also https://stackoverflow.com/questions/7142665/why-does-thread-isinterrupted-always-return-false – racraman Jun 28 '19 at 01:17

3 Answers3

2

It's because of how the interrupt flag works for a thread.

When you interrupt a thread, basically, only one thing happens: the interrupt flag is set, and that's all that happens. It is then up to the code that this thread is running whether that actually does stuff.

The general idea is that you abort what you're doing if you can and throw some sensible exception.

A few methods built into java guarantee that this is exactly how they work. You can recognize them easily: They are all declared to throw InterruptedException. There are many methods where behaviour when interrupting is intentionally undefined (it depends on the OS): All those blocking I/O methods act like this. If you are in a blocking network read and you interrupt the thread that's blocked on the read, that might result in an IOException on the read call, or.. not.

More importantly, when 'dealing' with an interrupt (and aborting + throwing an exception is dealing with it!), the flag is cleared.

Note that checking the flag already clears it, if you use the standard way of checking for it, which is Thread.interrupted(). This method checks your own thread's interrupt flag and clears it. Use this one: The fact that you've written an if statement or whatnot to deal with the interrupt means you dealt with it.

Thus, if you want to just return in response to being interrupted, the right code is:

    Runnable task = () -> {
        while (!Thread.interrupted()) {
            System.out.println("Executing");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                return;
            }
        }
    };

This method will just exit regardless of when the interrupt happens. In the 99.99% case itll happen whilst blocking on the sleep. Then the flag will be false, and the exception is thrown. In the unlikely case it occurs whilst processing outside of it, the while condition will pick it up.

Note that if you have the interrupt flag raised and you call a method like Thread.sleep, that method will instantly finish execution by clearing the flag and throwing InterruptedException. It doesn't matter where the interrupt happens, the above example will do the same thing (silently exit the run method, and the interrupt flag will be cleared).

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • thank you for the answer and apologies for a delay in the response. Going through your response am not clear on a few things: the code that you have - the only difference is that you have a return in the catch block and you are using '**Thread.interrupted()**' instead of '**Thread.currentThread().isInterrupted()**' . I tried both of these implementations with a return in a catch block - both work exactly the same – akila Jul 17 '19 at 05:41
  • another thing to note - not clear about the following: **Note that checking the flag already clears it, if you use the standard way of checking for it, which is Thread.interrupted(). This method checks your own thread's interrupt flag and clears it. Use this one: The fact that you've written an if statement or whatnot to deal with the interrupt means you dealt with it.** – akila Jul 17 '19 at 05:43
  • Thread.interrupted() checks the flag AND CLEARS IT; Thread.currentThread().isInterrupted() checks the flag, and that's it. You should clear the flag as you check it; the former is not just shorter, but 'better' and idiomatic java. I've explained it as well as I can; I don't understand how you're still confused. Whether the flag is still set or not after you're done with your handling of the interrupt has an effect only if the thread continues. If you're shutting it down, leaving the flag up doesn't break your application. It's just ugly code. – rzwitserloot Jul 18 '19 at 14:21
2

InterruptedException and Thread.isInterrupted() are actually quite independent. The complication was introduced when you used sleep() in the long-running loop. Your sleep(5000) is actually the one clearing your isInterrupted flag, and throwing the InterruptedException.

If you try the following, you'll see that there are actually no InterruptException thrown when you interrupt() the thread.

    @Override public void run() {
        int b = 0;
        while (true) {
            if (b++ == 0) System.out.println("running...");
        }
    }

Lesson is, you do need to check for both the exception and the flag, but they should not rely on each other. E.g. Your example catches the exception, but relies on the flag to exit your loop. As you have seen, this will not work.

You either need to break out of the while loop when the Exception was caught, or have your try/catch outside your loop (ensuring that catching the exception puts you out of the loop).

So, either one of the following should serve:

    while (!Thread.currentThread().isInterrupted()) { // out of the loop when flag is raised 
        try {   
            //......
        } 
        catch (InterruptedException e) { 
            break;//exit loop when exception thrown
        }
    }

    // Or:
    try {   
        while (!Thread.currentThread().isInterrupted()) { // exit loop when flag is raised
            //.....
        }
    } 
    catch (InterruptedException e) { 
        // no need to break, as we're already outside
    }
NPras
  • 3,135
  • 15
  • 29
1

Here is your code with a print statement.

public static void interrupted() throws InterruptedException {
      Runnable task = () ->
      {
         while (true && !Thread.currentThread().isInterrupted()) {
            System.out.println("task executing");
            try {
               Thread.sleep(5000);
            }
            catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
// this prints false.
               System.out.println(Thread.currentThread().isInterrupted());
            }
         }
      };

Once the interrupted state is processed, the thread is no longer considered to be in an interrupted state so the loop continues.

WJS
  • 36,363
  • 4
  • 24
  • 39
  • interesting thanks for this input but then in a real world example - if this spawned thread is trying to do some heavy weight operation ( database ) and is blocked - and we call interrupt on it - that would mean that the thread will never get interrupted correct ? – akila Jun 28 '19 at 01:09
  • Not necessarily. The thread did indeed get interrupted. But that condition does not necessarily last forever. Instead of doing a fixed `boolean` in the while loop, use a `flag` and set it to false in the `catch clause`. – WJS Jun 28 '19 at 01:15