8290036: Define and specify Runtime shutdown sequence

Reviewed-by: dholmes, alanb
This commit is contained in:
Stuart Marks 2022-10-05 23:43:02 +00:00
parent 0ec18382b7
commit d4142d8441
3 changed files with 143 additions and 115 deletions

View File

@ -44,10 +44,73 @@ import jdk.internal.reflect.Reflection;
* {@code Runtime} that allows the application to interface with
* the environment in which the application is running. The current
* runtime can be obtained from the {@code getRuntime} method.
* <p>
* An application cannot create its own instance of this class.
*
* <p>An application cannot create its own instance of this class.
*
* <h2><a id="shutdown">Shutdown Sequence</a></h2>
*
* <p>The Java Virtual Machine initiates the <i>shutdown sequence</i> in response
* to one of several events:
* <ol>
* <li>when the number of {@linkplain Thread#isAlive() live} non-daemon threads drops to zero
* for the first time (see note below on the JNI Invocation API);</li>
* <li>when the {@link #exit Runtime.exit} or {@link System#exit System.exit} method is called
* for the first time; or</li>
* <li>when some external event occurs, such as an interrupt or a signal is received from
* the operating system.</li>
* </ol>
*
* <p>At the beginning of the shutdown sequence, the registered shutdown hooks are
* {@linkplain Thread#start started} in some unspecified order. They run concurrently
* with any daemon or non-daemon threads that were {@linkplain Thread#isAlive() alive}
* at the beginning of the shutdown sequence.
*
* <p>After the shutdown sequence has begun, registration and de-registration of shutdown hooks
* with {@link #addShutdownHook addShutdownHook} and {@link #removeShutdownHook removeShutdownHook}
* is prohibited. However, creating and starting new threads is permitted. New threads run
* concurrently with the registered shutdown hooks and with any daemon or non-daemon threads
* that are already running.
*
* <p>The shutdown sequence finishes when all shutdown hooks have terminated. At this point,
* the Java Virtual Machine terminates as described below.
*
* <p>It is possible that one or more shutdown hooks do not terminate, for example, because
* of an infinite loop. In this case, the shutdown sequence will never finish. Other threads
* and shutdown hooks continue to run and can terminate the JVM via the {@link #halt halt} method.
*
* <p>Prior to the beginning of the shutdown sequence, it is possible for a program to start
* a shutdown hook by calling its {@link Thread#start start} method explicitly. If this occurs, the
* behavior of the shutdown sequence is unspecified.
*
* <h2><a id="termination">Java Virtual Machine Termination</a></h2>
*
* <p>The JVM terminates when the shutdown sequence finishes or when {@link #halt halt} is called.
* In contrast to {@link #exit exit}, the {@link #halt halt} method does not initiate the
* shutdown sequence.
*
* <p>When the JVM terminates, all threads are immediately prevented from executing any further
* Java code. This includes shutdown hooks as well as daemon and non-daemon threads. The
* threads' current methods do not complete normally or abruptly; no {@code finally} clause
* of any method is executed, nor is any {@linkplain Thread.UncaughtExceptionHandler
* uncaught exception handler}.
*
* @implNote
* Native code typically uses the
* <a href="{@docRoot}/../specs/jni/invocation.html">JNI Invocation API</a>
* to control launching and termination of the JVM. Such native code invokes the
* <a href="{@docRoot}/../specs/jni/invocation.html#jni_createjavavm">{@code JNI_CreateJavaVM}</a>
* function to launch the JVM. Subsequently, the native code invokes the
* <a href="{@docRoot}/../specs/jni/invocation.html#destroyjavavm">{@code DestroyJavaVM}</a>
* function to await termination of that JVM. The {@code DestroyJavaVM} function is responsible
* for initiating the shutdown sequence when the number of {@linkplain Thread#isAlive() live}
* non-daemon threads first drops to zero. When the shutdown sequence completes and the JVM
* terminates, control is returned to the native code that invoked {@code DestroyJavaVM}. This
* behavior differs from the {@link #exit exit} or {@link #halt halt} methods. These methods
* typically terminate the OS process hosting the JVM and do not interact with the JNI Invocation
* API.
*
* @see java.lang.Runtime#getRuntime()
* @jls 12.8 Program Exit
* @since 1.0
*/
@ -72,21 +135,19 @@ public class Runtime {
private Runtime() {}
/**
* Terminates the currently running Java virtual machine by initiating its
* shutdown sequence. This method never returns normally. The argument
* serves as a status code; by convention, a nonzero status code indicates
* abnormal termination.
*
* <p> All registered {@linkplain #addShutdownHook shutdown hooks}, if any,
* are started in some unspecified order and allowed to run concurrently
* until they finish. Once this is done the virtual machine
* {@linkplain #halt halts}.
* Initiates the <a href="#shutdown">shutdown sequence</a> of the Java Virtual Machine.
* This method blocks indefinitely; it never returns or throws an exception (that is, it
* does not complete either normally or abruptly). The argument serves as a status code;
* by convention, a nonzero status code indicates abnormal termination.
*
* <p> Invocations of this method are serialized such that only one
* invocation will actually proceed with the shutdown sequence and
* terminate the VM with the given status code. All other invocations
* will block indefinitely. If this method is invoked from a shutdown
* hook the system will deadlock.
* simply block indefinitely.
*
* <p> Because this method always blocks indefinitely, if it is invoked from
* a shutdown hook, it will prevent that shutdown hook from terminating.
* Consequently, this will prevent the shutdown sequence from finishing.
*
* <p> The {@link System#exit(int) System.exit} method is the
* conventional and convenient means of invoking this method.
@ -118,85 +179,46 @@ public class Runtime {
/**
* Registers a new virtual-machine shutdown hook.
*
* <p> The Java virtual machine <i>shuts down</i> in response to two kinds
* of events:
* <p> A <i>shutdown hook</i> is simply an initialized but unstarted thread. Shutdown hooks
* are started at the beginning of the <a href="#shutdown">shutdown sequence</a>.
* Registration and de-registration of shutdown hooks is disallowed once the shutdown
* sequence has begun.
* <p>
* Uncaught exceptions are handled in shutdown hooks just as in any other thread, as
* specified in {@link Thread.UncaughtExceptionHandler}. After the uncaught exception
* handler has completed, the shutdown hook is considered to have terminated and is not
* treated differently from a hook that has terminated without having thrown an
* uncaught exception.
*
* <ul>
*
* <li> The program <i>exits</i> normally, when the last non-daemon
* thread exits or when the {@link #exit exit} (equivalently,
* {@link System#exit(int) System.exit}) method is invoked, or
*
* <li> The virtual machine is <i>terminated</i> in response to a
* user interrupt, such as typing {@code ^C}, or a system-wide event,
* such as user logoff or system shutdown.
*
* </ul>
*
* <p> A <i>shutdown hook</i> is simply an initialized but unstarted
* thread. When the virtual machine begins its shutdown sequence it will
* start all registered shutdown hooks in some unspecified order and let
* them run concurrently. When all the hooks have finished it will then
* halt. Note that daemon threads will continue to run during the shutdown
* sequence, as will non-daemon threads if shutdown was initiated by
* invoking the {@link #exit exit} method.
*
* <p> Once the shutdown sequence has begun it can be stopped only by
* invoking the {@link #halt halt} method, which forcibly
* terminates the virtual machine.
*
* <p> Once the shutdown sequence has begun it is impossible to register a
* new shutdown hook or de-register a previously-registered hook.
* Attempting either of these operations will cause an
* {@link IllegalStateException} to be thrown.
*
* <p> Shutdown hooks run at a delicate time in the life cycle of a virtual
* machine and should therefore be coded defensively. They should, in
* @apiNote
* Shutdown hooks run at a delicate time in the life cycle of a virtual
* machine and should therefore be coded defensively. They should, in
* particular, be written to be thread-safe and to avoid deadlocks insofar
* as possible. They should also not rely blindly upon services that may
* have registered their own shutdown hooks and therefore may themselves in
* the process of shutting down. Attempts to use other thread-based
* as possible. They should also not rely blindly upon services that may
* have registered their own shutdown hooks and therefore may themselves be
* in the process of shutting down. Attempts to use other thread-based
* services such as the AWT event-dispatch thread, for example, may lead to
* deadlocks.
*
* <p> Shutdown hooks should also finish their work quickly. When a
* program invokes {@link #exit exit} the expectation is
* <p>
* Shutdown hooks should also finish their work quickly. When a
* program invokes {@link #exit exit}, the expectation is
* that the virtual machine will promptly shut down and exit. When the
* virtual machine is terminated due to user logoff or system shutdown the
* underlying operating system may only allow a fixed amount of time in
* which to shut down and exit. It is therefore inadvisable to attempt any
* underlying operating system may only allow a limited amount of time in
* which to shut down and exit. It is therefore inadvisable to attempt any
* user interaction or to perform a long-running computation in a shutdown
* hook.
*
* <p> Uncaught exceptions are handled in shutdown hooks just as in any
* other thread, by invoking the
* {@link ThreadGroup#uncaughtException uncaughtException} method of the
* thread's {@link ThreadGroup} object. The default implementation of this
* method prints the exception's stack trace to {@link System#err} and
* terminates the thread; it does not cause the virtual machine to exit or
* halt.
*
* <p> In rare circumstances the virtual machine may <i>abort</i>, that is,
* stop running without shutting down cleanly. This occurs when the
* virtual machine is terminated externally, for example with the
* {@code SIGKILL} signal on Unix or the {@code TerminateProcess} call on
* Microsoft Windows. The virtual machine may also abort if a native
* method goes awry by, for example, corrupting internal data structures or
* attempting to access nonexistent memory. If the virtual machine aborts
* then no guarantee can be made about whether or not any shutdown hooks
* will be run.
*
* @param hook
* An initialized but unstarted {@link Thread} object
*
* @throws IllegalArgumentException
* If the specified hook has already been registered,
* or if it can be determined that the hook is already running or
* has already been run
* If the same hook (compared using {@code ==}) as the specified hook has
* already been registered, or if it can be determined that the hook is
* already running or has already been run
*
* @throws IllegalStateException
* If the virtual machine is already in the process
* of shutting down
* If the shutdown sequence has already begun
*
* @throws SecurityException
* If a security manager is present and it denies
@ -218,6 +240,9 @@ public class Runtime {
/**
* De-registers a previously-registered virtual-machine shutdown hook.
* Hooks are compared using {@code ==}.
* Registration and de-registration of shutdown hooks is disallowed
* once the shutdown sequence has begun.
*
* @param hook the hook to remove
* @return {@code true} if the specified hook had previously been
@ -225,8 +250,7 @@ public class Runtime {
* otherwise.
*
* @throws IllegalStateException
* If the virtual machine is already in the process of shutting
* down
* If the shutdown sequence has already begun
*
* @throws SecurityException
* If a security manager is present and it denies
@ -246,14 +270,15 @@ public class Runtime {
}
/**
* Forcibly terminates the currently running Java virtual machine. This
* method never returns normally.
* Immediately <a href="#termination">terminates</a> the Java Virtual Machine. Termination
* is unconditional and immediate. This method does not initiate the
* <a href="#shutdown">shutdown sequence</a>, nor does it wait for the shutdown sequence
* to finish if it is already in progress. This method never returns normally.
*
* <p> This method should be used with extreme caution. Unlike the
* {@link #exit exit} method, this method does not cause shutdown
* hooks to be started. If the shutdown sequence has already been
* initiated then this method does not wait for any running
* shutdown hooks to finish their work.
* @apiNote
* This method should be used with extreme caution. Using it may circumvent or disrupt
* any cleanup actions intended to be performed by shutdown hooks, possibly leading to
* data corruption.
*
* @param status
* Termination status. By convention, a nonzero status code

View File

@ -1885,24 +1885,24 @@ public final class System {
}
/**
* Terminates the currently running Java Virtual Machine. The
* argument serves as a status code; by convention, a nonzero status
* code indicates abnormal termination.
* Initiates the <a href="Runtime.html#shutdown">shutdown sequence</a> of the
* Java Virtual Machine. This method always blocks indefinitely. The argument
* serves as a status code; by convention, a nonzero status code indicates
* abnormal termination.
* <p>
* This method calls the {@code exit} method in class
* {@code Runtime}. This method never returns normally.
* This method calls the {@code exit} method in class {@code Runtime}. This
* method never returns normally.
* <p>
* The call {@code System.exit(n)} is effectively equivalent to
* the call:
* The call {@code System.exit(n)} is effectively equivalent to the call:
* <blockquote><pre>
* Runtime.getRuntime().exit(n)
* </pre></blockquote>
*
* @param status exit status.
* @throws SecurityException
* if a security manager exists and its {@code checkExit}
* method doesn't allow exit with the specified status.
* @see java.lang.Runtime#exit(int)
* @param status exit status.
* @throws SecurityException
* if a security manager exists and its {@code checkExit} method
* doesn't allow exit with the specified status.
* @see java.lang.Runtime#exit(int)
*/
public static void exit(int status) {
Runtime.getRuntime().exit(status);

View File

@ -52,7 +52,6 @@ import jdk.internal.vm.ExtentLocalContainer;
import jdk.internal.vm.StackableScope;
import jdk.internal.vm.ThreadContainer;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.vm.annotation.Stable;
import sun.nio.ch.Interruptible;
import sun.security.util.SecurityConstants;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
@ -63,11 +62,16 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS;
* virtual machine allows an application to have multiple threads of
* execution running concurrently.
*
* <p> {@code Thread} defines constructors and a {@link Builder} to create threads
* that execute {@link Runnable} tasks. {@linkplain #start() Starting} a thread
* schedules it to execute concurrently with the thread that caused it to start.
* The newly started thread invokes the task's {@link Runnable#run() run} method.
* Thread defines the {@link #join() join} method to wait for a thread to terminate.
* <p> {@code Thread} defines constructors and a {@link Builder} to create threads.
* {@linkplain #start() Starting} a thread schedules it to execute its {@link #run() run}
* method. The newly started thread executes concurrently with the thread that caused
* it to start.
*
* <p> A thread <i>terminates</i> if either its {@code run} method completes normally,
* or if its {@code run} method completes abruptly and the appropriate {@linkplain
* Thread.UncaughtExceptionHandler uncaught exception handler} completes normally or
* abruptly. With no code left to run, the thread has completed execution. The
* {@link #join() join} method can be used to wait for a thread to terminate.
*
* <p> Threads have a unique {@linkplain #threadId() identifier} and a {@linkplain
* #getName() name}. The identifier is generated when a {@code Thread} is created
@ -94,11 +98,9 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS;
* <p> Platform threads are designated <i>daemon</i> or <i>non-daemon</i> threads.
* When the Java virtual machine starts up, there is usually one non-daemon
* thread (the thread that typically calls the application's {@code main} method).
* The Java virtual machine terminates when all started non-daemon threads have
* terminated. Unstarted non-daemon threads do not prevent the Java virtual machine
* from terminating. The Java virtual machine can also be terminated by invoking
* the {@linkplain Runtime#exit(int)} method, in which case it will terminate even
* if there are non-daemon threads still running.
* The <a href="Runtime.html#shutdown">shutdown sequence</a> begins when all started
* non-daemon threads have terminated. Unstarted non-daemon threads do not prevent
* the shutdown sequence from beginning.
*
* <p> In addition to the daemon status, platform threads have a {@linkplain
* #getPriority() thread priority} and are members of a {@linkplain ThreadGroup
@ -124,9 +126,10 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS;
* <p> Virtual threads do not have a thread name by default. The {@link #getName()
* getName} method returns the empty string if a thread name is not set.
*
* <p> Virtual threads are daemon threads and so do not prevent the Java virtual
* machine from terminating. Virtual threads have a fixed {@linkplain #getPriority()
* thread priority} that cannot be changed.
* <p> Virtual threads are daemon threads and so do not prevent the
* <a href="Runtime.html#shutdown">shutdown sequence</a> from beginning.
* Virtual threads have a fixed {@linkplain #getPriority() thread priority}
* that cannot be changed.
*
* <h2>Creating and starting threads</h2>
*
@ -2200,10 +2203,10 @@ public class Thread implements Runnable {
/**
* Marks this thread as either a <i>daemon</i> or <i>non-daemon</i> thread.
* The Java virtual machine terminates when all started non-daemon threads have
* terminated.
* The <a href="Runtime.html#shutdown">shutdown sequence</a> begins when all
* started non-daemon threads have terminated.
*
* The daemon status of a virtual thread is always {@code true} and cannot be
* <p> The daemon status of a virtual thread is always {@code true} and cannot be
* changed by this method to {@code false}.
*
* <p> This method must be invoked before the thread is started. The behavior