JDK-8221657 : java.lang.Thread::setDaemon modifies the state of terminated threads
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 13
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2019-03-29
  • Updated: 2022-06-19
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.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
The specification of Thread::setDaemon states:

  * <p> This method must be invoked before the thread is started.

but then has:

    * @throws  IllegalThreadStateException
    *          if this thread is {@linkplain #isAlive alive}

and is implemented with:

 public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

The problem is that  not isAlive() is not the same as "before the thread has started" as a terminated thread is not alive. Hence the code allows the daemon state of a terminated thread to change - contrary to (at least part of) the specification.

This issue was discovered while investigating an apparent bug in the VM tracking the number of daemon threads - see JDK-8218483.

Given we can fix JDK-8218483 in the VM, and that this is a long standing "bug" it may not be worth fixing.
Comments
Yes, setDaemon on a platform thread should be synchronized with start. As regards the API docs then it is unfortunate that the setDaemon method was specified to throw the exception when the thread is alive, it should probably have been specified to throw the exception if thread was started so it is consistent with Thread.start. Changing it now to throw the exception when the thread is terminated would be an incompatible change (although unlikely that there is a lot of code that would be impacted). The simplest thing may be to document long standing behavior.
19-06-2022

By the way, setDaemon should also be synchronized so that you can't have a race between one thread calling setDaemon(true) and another thread calling start() on it. The change of state has to be atomic with respect to the isAlive() check.
01-04-2019