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.