10

Consider the following JUnit test:

@Test
public void testSettingInterruptFlag() throws InterruptedException {

    Thread blockingThread = new Thread(new Runnable() {
        @Override
        public synchronized void run() {

            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    });
    blockingThread.start();
    blockingThread.interrupt();
    blockingThread.join();
    assertTrue(blockingThread.isInterrupted());
}

The test fails even though the interrupted status was set. I've suspected that the line blockingThread.join(); resets the flag but even when replacing that line with Thread.sleep(3000); the test still fails. Is this behaviour documented anywhere?

Lovro Pandžić
  • 5,920
  • 4
  • 43
  • 51
  • 1
    Have you tried putting `sleep(1000)` _before_ the call to consumerThread.interrupt()? Starting a thread is a native call, but I'm not sure there's any guarantee that the thread has actually started running after the call to start completes. – Ash Jan 07 '14 at 10:48
  • Yeah, my guess was wrong, Alexei's answer below seems to explain the symptoms. – Ash Jan 07 '14 at 13:53

3 Answers3

5

what we see is that interrupted status of a thread is cleared when that thread finishes. It is not documented in http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html, so can be considered as a spec or implementation bug.

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38
  • Currently it seems that this behavior is implementation detail since I've found no mention of this specific case in language specification. – Lovro Pandžić Jan 07 '14 at 14:06
4

This has been fixed in Java 14.

Thread.isInterrupted returns true if the thread was interrupted, even if the thread is not alive. See Oracle's release notes and JDK-8229516.

The specification for java.lang.Thread::interrupt allows for an implementation to only track the interrupt state for live threads, and previously this is what occurred. As of this release, the interrupt state of a Thread is always available, and if you interrupt a thread t before it is started, or after it has terminated, the query t.isInterrupted() will return true.

The following paragraph has been added to the javadoc of Thread#interrupt:

In the JDK Reference Implementation, interruption of a thread that is not alive still records that the interrupt request was made and will report it via interrupted and isInterrupted().

So the test in the question runs successfully on:

openjdk version "14.0.2" 2020-07-14
OpenJDK Runtime Environment (build 14.0.2+12)
OpenJDK 64-Bit Server VM (build 14.0.2+12, mixed mode)

The interruption flag is stored as a field in the Thread class:

/* Interrupt state of the thread - read/written directly by JVM */
private volatile boolean interrupted;

and isInterrupted method simply returns the flag:

public boolean isInterrupted() {
    return interrupted;
}

previously it delegated to a native isInterrupted(boolean) method

Denis Zavedeev
  • 7,627
  • 4
  • 32
  • 53
0

From the JavaDocs: "A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by this method returning false."

Your thread had not started yet when you called "Thread.interrupt()".

Making unit tests for concurrent systems is pretty tricky. You can make it slightly more robust by adding a delay into the test but that unfortunately slows down the test execution so you can not have a lot of them.

To make it fail safe you need to add a boolean flag to the thread class that tells the test that it has started and wait for that flag to be raised in a busy loop. Only then you can call interrupt and join.

Torben
  • 3,805
  • 26
  • 31
  • That explanation does not match the behaviour I get when running the test. You are right that the blockingThread may not have reached the invocation of wait() before it is interrupted, but even if it did, the interrupted status is obviously cleared when the thread dies, just as Alexei points out. – jarnbjo Jan 07 '14 at 12:38
  • I've tested this situation with sleep and the result is always the same. All clues point to the flag being reset on thread termination. – Lovro Pandžić Jan 08 '14 at 07:29