/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.lang;
import java.util.*;
/*
* Class to track and run user level shutdown hooks registered through
* <tt>{@link Runtime#addShutdownHook Runtime.addShutdownHook}</tt>.
*
* @see java.lang.Runtime#addShutdownHook
* @see java.lang.Runtime#removeShutdownHook
*/
class
ApplicationShutdownHooks {
/* The set of registered hooks */
private static
IdentityHashMap<
Thread,
Thread>
hooks;
static {
try {
Shutdown.
add(1 /* shutdown hook invocation order */,
false /* not registered if shutdown in progress */,
new
Runnable() {
public void
run() {
runHooks();
}
}
);
hooks = new
IdentityHashMap<>();
} catch (
IllegalStateException e) {
// application shutdown hooks cannot be added if
// shutdown is in progress.
hooks = null;
}
}
private
ApplicationShutdownHooks() {}
/* Add a new shutdown hook. Checks the shutdown state and the hook itself,
* but does not do any security checks.
*/
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);
}
/* Remove a previously-registered hook. Like the add method, this method
* does not do any security checks.
*/
static synchronized boolean
remove(
Thread hook) {
if(
hooks == null)
throw new
IllegalStateException("Shutdown in progress");
if (
hook == null)
throw new
NullPointerException();
return
hooks.
remove(
hook) != null;
}
/* Iterates over all application hooks creating a new thread for each
* to run in. Hooks are run concurrently and this method waits for
* them to finish.
*/
static void
runHooks() {
Collection<
Thread>
threads;
synchronized(
ApplicationShutdownHooks.class) {
threads =
hooks.
keySet();
hooks = null;
}
for (
Thread hook :
threads) {
hook.
start();
}
for (
Thread hook :
threads) {
while (true) {
try {
hook.
join();
break;
} catch (
InterruptedException ignored) {
}
}
}
}
}