-1

Assume the below code is executed with a debugger so that we can predict the order of execution.

  • t1 -- Here task1 starts working on some long task.
  • t2 --- task2 gets blocked @ Syncronized statement because task1 is holding lock.
  • t3 -- task2 is interrupted but its missed because task2 is using intrinsic locks and hence cannot be interrupted @ synchronized. (Renenterant.lockInterruptible() would have thrown InterruptedExecption).
  • t4 --- task1 is interrupted. However despite of doing the complex task in try catch block, InterruptedExecption was never thrown. Why is that ?

Code:

public class TestInteruptibility {
    public static Object lock = new Object();
    public static boolean spin = true;

    public static void main(String[] args) {
        Thread task1 = new Thread(new Task(), "Task1");
        Thread task2 = new Thread(new Task(), "Task2");
        Thread notifier1 = new Thread(new Notifier(), "Notifier1");
        task1.start();
        task2.start();
        task2.interrupt();
        task1.interrupt();
        notifier1.start();
    }
}

class Task implements Runnable {
    public void run() {
        synchronized (TestInteruptibility.lock) {
            System.out.println("Performing Long Task");
            try {
                while (TestInteruptibility.spin) {
                }
                System.out.println("Finsihed Performing Long Task");
                TestInteruptibility.lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("I got interrupted while i was waiting @ wait()");
            }
            System.out.println("Ending Task");
        }
    }
}

class Notifier implements Runnable {
    public void run() {
        synchronized (TestInteruptibility.lock) {
            System.out.println("Performing notification");
            TestInteruptibility.lock.notify();
            System.out.println("Ending notification");
        }
    }
}
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
deepujain
  • 657
  • 1
  • 10
  • 17
  • `spin` is never false, the loop never terminates and you never see "Finsihed [sic] Performing Long Task". – erickson Mar 17 '13 at 06:45

3 Answers3

3

Basically, what interrupt() does is to set a flag in the Thread object. And you need to check it with isInterrupted(). Then you can handle this interrupt signal. It won't throw an InterruptedException in this situation.

Besides, it can cause some methods, for example, Thread.sleep(), Object.wait(), to return immediately and throw an InterruptedException. And you can get and InterruptedException in this situation.

From Java Concurrency in Practice, 7.1.1. Interruption:

A good way to think about interruption is that it does not actually interrupt a running thread; it just requests that the thread interrupt itself at the next convenient opportunity. (These opportunities are called cancellation points.) Some methods, such as wait, sleep, and join, take such requests seriously, throwing an exception when they receive an interrupt request or encounter an already set interrupt status upon entry. Well behaved methods may totally ignore such requests so long as they leave the interruption request in place so that calling code can do something with it. Poorly behaved methods swallow the interrupt request, thus denying code further up the call stack the opportunity to act on it.

In your above code, you are not waiting/sleeping. So you have to check isInterrupted() and handle interrupt signal yourself in the while loop.

while (TestInteruptibility.spin) {
    if (Thread.currentThread().isInterrupted()) {
        break;
    }
}

References:

  1. why interrupt() not work as expected and how does it work
  2. What does java.lang.Thread.interrupt() do?
Community
  • 1
  • 1
longhua
  • 4,142
  • 21
  • 28
2

You have a busy while loop, that holds the lock (and never ends, unless you change spin's value somewhere). I suppose that task1 is still in the loop, therefore it doesn't notice the interruption. Task2 can't acquire the lock, so it blocks.

The way Task is implemented, it can only be interrupted in during the wait command, which comes after the loop.

BTW: if you are using the spin data member in different threads, then it should probably be declared as volatile. For similar thread safety reasons, lock should be declared as final.

Eyal Schneider
  • 22,166
  • 5
  • 47
  • 78
0

When you call method interrupt() the result depends on the this thread is doing currently. If it is blocked on some interruptable method such as Object.wait(), then it will be interrupted immediately, which means that InterruptedException will be throw inside the thread. If thread is not blocked, but is doing some calculations, or it is block on some non-interruptable method such as InputStream.read() then InterruptedException is not thrown, but interrupted flag is set on thread instead. This flag will cause InterruptedException next time thread will call some interruptable method, but not now.

In your case threads task1 and task2 are spinning in infinite empty loops and thus are not blocked on any interruptable methods, so when you call interrupt() on then, no InterruptedException is thrown inside that threads, but interrupted flag is just set. You probably should change your task code to look like this:

while (TestInteruptibility.spin && !Thread.interrupted ()) {
}

then you will exit from the loop as long as somebody will call interrupt on task thread.

Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
  • That condition would be a good one to test. In addition, though, `spin` must be declared as a `volatile` field, so that visibility is guaranteed. – erickson Mar 17 '13 at 07:06
  • I am not able to answer my question with a fix using ReentrantLock.lockInterruptibility() – deepujain Mar 17 '13 at 08:49