Using Thread.currentThread().isInterrupted() with Thread.sleep()

2.9k views Asked by At

I have a thread that calls a work() method which is a simple while(true)-loop as below;

public void work() throws InterruptedException {
    while (true) {
        // PART A
        if (Thread.currentThread().isInterrupted()) {
            System.out.println("....run()::work::PART A::isInterrupted():" + Thread.currentThread().isInterrupted());
            Thread.sleep(2000);
        }

        // Is it possible to make the below code executable at runtime when thread is interrupted?
        // PART B
        if (Thread.currentThread().isInterrupted()) {
            System.out.println("....run()::work::PART B::isInterrupted():" + Thread.currentThread().isInterrupted());
            Thread.sleep(2000);
        }
    }
}

I run this thread instance and interrupt the thread from the main after a period of time with Thread.sleep() method. As I change the delay, I expect to hit the commented part when the thread is interrupted from the main thread but I only see the output below;

....run()::Work::starting
.main()::interrupting thread t
.main()::leaving
....run()::work::PART A::isInterrupted():true
....run()::Work::ERROR::INTERRUPTED

My simple question is this, is it possible to execute the second part (Part B) of the work() method, or if not, why?

The complete demo is as below;

public class GeneralInterrupt implements Runnable {
    public void run() {
        try {
            System.out.println("....run()::Work::starting");
            work();
            System.out.println("....run()::Work::ended");
        } catch (InterruptedException x) {
            System.out.println("....run()::Work::ERROR::INTERRUPTED");
            return;
        }
        System.out.println("....run()::Work::leaving normally");
    }

    public void work() throws InterruptedException {
        while (true) {
            // PART A
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("....run()::work::PART A::isInterrupted():" + Thread.currentThread().isInterrupted());
                Thread.sleep(2000);
            }

            // Is it possible to make the below code executable at runtime when thread is interrupted?
            // PART B
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("....run()::work::PART B::isInterrupted():" + Thread.currentThread().isInterrupted());
                Thread.sleep(2000);
            }
        }
    }

    public static void main(String[] args) {
        Thread t = new Thread(new GeneralInterrupt());
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException x) {
        }
        System.out.println(".main()::interrupting thread t");
        t.interrupt();
        System.out.println(".main()::leaving");
    }
}

Please also notify that, if the "Thread.sleep(2000)" lines are both removed from the A and B part, then the output is

....run()::work::PART B::isInterrupted():false
....run()::work::PART B::isInterrupted():false
....run()::work::PART B::isInterrupted():false
....run()::work::PART B::isInterrupted():false
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true

Can anybody explain why Thread.sleep() method is behaving in such a way inside the work() method.

3

There are 3 answers

0
K Erlandsson On

When you interrupt the thread and it is in the sleep method, sleep will throw an InterruptedException. You do not handle this exception. It is propagated to your run method and your while loop exits.

You need to surround your sleep with a try/catch and catch InterruptedException. You must also be sure to call Thread.currentThread().interrupt() after catching it, if you want isInterrupted() to return true after the exception, since the exception will reset the interrupt flag. Like this:

     if (Thread.currentThread().isInterrupted()) {
         System.out.println("....run()::work::PART A::isInterrupted():" 
             + Thread.currentThread().isInterrupted());
         try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
     }
0
Thomas On

As per Oracle Tutorial, interrupting a thread is a signal to the thread to end its current work and do something else (like terminating):

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate. This is the usage emphasized in this lesson.

Thus it should generally be possible to continue after an interrupt.

As per JavaDoc on interrupts, it depends on where the thread is interrupted:

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. (emphasis added by me)

That's why you get the exception when using sleep(2000).

0
user207421 On

Thread.isInterrupted() doesn't clear the interrupted status of the thread. So when you call sleep(), an InterruptedException is thrown. You need to call Thread.interrupted() instead of Thread.currentThread().isInterrupted().

However that will mean that Part B will only execute if an interrupt occurred during the sleep after Part A, which appears to be what you want. If you need Part B to run whenever Part A runs, put it into the same block instead of after a second test.