Lovro Pandžić
Lovro Pandžić

Reputation: 6380

Thread.isInterrupted() returns false after thread has been terminated

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?

Upvotes: 10

Views: 1048

Answers (3)

Denis Zavedeev
Denis Zavedeev

Reputation: 8297

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

Upvotes: 5

Torben
Torben

Reputation: 3913

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.

Upvotes: 0

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13535

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.

Upvotes: 5

Related Questions