JDK-8229516 : Thread.isInterrupted() always returns false after thread termination
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 14
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2019-08-13
  • Updated: 2019-11-12
  • Resolved: 2019-11-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 14
14 b22Fixed
Related Reports
Blocks :  
CSR :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8234771 :  
Description
I was surprised that interrupt status was not preserved on thread termination.  E.g. as demonstrated by:

```
public class PostTerminationInterruptStatus {
    static int countInterrupted(Thread[] threads) {
        int count = 0;
        for (Thread thread : threads)
            if (thread.isInterrupted())
                count++;
        return count;
    }

    public static void main(String[] args) throws Throwable {
        final int n = 3;
        final Thread[] threads = new Thread[n];
        for (int i = 0; i < n; i++) {
            threads[i] = new Thread(() -> Thread.currentThread().interrupt());
            threads[i].start();
        }
        System.out.println("" + countInterrupted(threads));
        for (Thread thread : threads) thread.join();
        System.out.println("" + countInterrupted(threads));
    }
}
```

The spec for Thread.interrupt and Thread.isInterrupted say that Thread.interrupt need not have any effect when the target thread has terminated BUT are silent on the question of what happens when Thread.isInterrupted is called when the target thread has terminated.  Which suggests that the interrupt status needs to be preserved.

The behavior of Thread is more understandable if we are aware of the implementation maintaining VM-internal state that contains the interrupt status, and that state is discarded on termination.

Currently there is no non-intrusive way of asking whether a thread terminated with the interrupt status set.

JDK developer lore is that the interrupt status was once a field in the java-level Thread class.  I think it should be restored.

Comments
I overlooked a subtlety here that is causing problems - see JDK-8233549. To access a field of a Java object a thread must be in the correct safepoint state, else the object could be moved by GC whilst we are accessing it.
06-11-2019

URL: https://hg.openjdk.java.net/jdk/jdk/rev/2700c409ff10 User: dholmes Date: 2019-11-03 23:02:52 +0000
03-11-2019

The actual move is quite straight-forward (as long as you take care to preserve the current structure - thanks [~pchilanomate] for debugging that!). In addition we no longer need an intrinsic for Thread.isInterrupted so there are also changes to the JIT compiler code, in particular JVMCI.
29-10-2019

Just to update things the reshuffling has been done and interrupt mechanics are now isolated to JavaThread and the underlying osThread. We can't quite get rid of osThread as Windows has a special interrupt event for use by Process.waitFor.
11-10-2019

Things are a bit messy on the VM side. Thread interruption is inherently about java.lang.Threads but interrupt support in the VM applies (potentially at least) to all threads. If we actually move that support to JavaThread we enable the move to storing interrupt state in the j.l.Thread instance. This involves a bit of re-shuffling and refactoring before we actually get to the point of moving the interrupt state to j.l.Thread.
22-08-2019

We probably want fibers and threads not to differ gratuitously. Which strengthens the case for moving thread interrupt status into a proper Java field. (But ... it's true that querying __another__ thread's interrupt status is a very weird thing to do. I mostly care because I'm writing tests to check proper handling of the interrupt status, but it's easy enough to rewrite any such tests so that the thread (or fiber) can check its own interrupt status just before terminating.)
14-08-2019

This seems to be a long standing "issue" but not something that many will notice. User mode threads don't have any VM meta data so the interrupt status has to be stored in a Java object. If the carrier thread interrupt status moves to be a bit or field in a Java object then it should matter, it just needs careful coordination when forwarding to keep the status in sync when mounted.
14-08-2019

>> There is no specification being violated here We'll just have to disagree here. Maybe I'm too pedantic-minded or David has spent too much time as a hotspot engineer.
14-08-2019

If an extra field is an issue it may be possible to simply steal the low-order bit of "eeTop" as the interrupt state. The eeTop field (named historically for "execution environment top" is a Java long that actually holds the raw value of the JavaThread address for the Thread's native VM thread. It is set when the Thread is started and cleared as part of the termination process - a non-zero value of this field indicates the Thread "isAlive".
13-08-2019

Moved to hotspot->runtime as most of the impact is in the VM. There is no specification being violated here so I've made this an enhancement request rather than a bug. Arguably the lack of specification is a bug - we did intentionally specify that "interrupt after termination need have no affect" to deal with the fact that the interrupt state is stored in the VM and no longer exists once a thread has terminated. However we neglected to reflect that in the Thread.isInterrupted spec. There is a glitch in the current implementation in that it does not always return false. There is a small window during the thread termination sequence, in which Thread.join() will return because the thread is no longer "alive" but the VM native thread is still in the process of being cleaned up (it may be "trapped" by a ThreadsListIterator for example; or just hasn't executed all the termination logic yet), during which time the true interrupt state can still be reported. If we were to fix the specification to say we always return false after termination then this would have to be fixed. But as Martin and I have discussed there is another possibility here and that is to "simply" do away with maintaining the interrupt state in the VM and just keep it as a field of Thread. Jumping in the wayback machine ... Way back in March 1996 Thread.java had: /* Indicator of whether this thread has been interrupted */ private boolean interruptRequested = false; public void interrupt() { // Note that this method is not syncronized. Three reasons for this: // 1) It changes the API // 2) It's another place where the system could hang. // 3) All we're doing is turning on a one-way bit. It doesn't matter // exactly when it's done wrt probes via the interrupted() function. interruptRequested = true; } but by June 1996 it was all moved into native code in the VM. Exactly why I can't be certain but it likely relates to how interrupt needed to "unpark" blocked threads. Possibly in some conditions the thread doing the unblocking may not have been able to touch the j.l.Thread object - but that's speculation on my part. I can't, off the top of my head, see any reason why this couldn't just be a field in Thread, instead of a field in the native thread representation. But I would not be surprised to (re)discover there is a reason something so simple doesn't work. The Thread field would still have to be set via native code in the VM, but at least it would be queryable directly from Java and when the Thread is not alive (both before starting and after termination). It might be an interesting experiment, and if we got rid of the interrupt state from OSThread that may make it easier to get rid of OSThread (as we wanted to do in the past). That said, adding an extra field to Thread is not to be done lightly. In particular this may be of concern for Project Loom due to its use of "shadow" Threads for each Fiber.
13-08-2019

Most of the work for this bug would be in the VM, so it may belong in some other component.
13-08-2019