JDK-8221893 : ApplicationShutdownHook: Thread.isAlive() is not equivalent to not being startable
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 13
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2019-04-03
  • Updated: 2019-04-04
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 :  
Description
As reported by Thomas Stuefe in:

http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2019-April/033512.html

ApplicationShutdownHook.java:

static synchronized void add(Thread hook) {
    if(hooks == null)
        throw new IllegalStateException("Shutdown in progress");

    if (hook.isAlive())
        throw new IllegalArgumentException("Hook already running");

    if (hooks.containsKey(hook))
        throw new IllegalArgumentException("Hook previously registered");

    hooks.put(hook, hook);
}

would register a terminated thread as shutdown hook.
---

When start that hook we would get an IllegalThreadStateException that would terminate the hook starting and joining logic:

    static void runHooks() {
        Collection<Thread> threads;
        synchronized(ApplicationShutdownHooks.class) {
            threads = hooks.keySet();
            hooks = null;
        }

        for (Thread hook : threads) {
            hook.start();  <= // BOOM!
        }
        for (Thread hook : threads) {
            while (true) {
                try {
                    hook.join();
                    break;
                } catch (InterruptedException ignored) {
                }
            }
        }
    }

We need to check for getState() == Thread.State.NEW