net.sf.eBus.util.ShutdownHook Maven / Gradle / Ivy
//
// Copyright 2013 Charles W. Rapp
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package net.sf.eBus.util;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Provides a simple way for an console-based, Java application
* main thread to wait until the virtual machine terminates. If
* an application main method is solely responsible for setting
* up and tearing down the application and hands off control to
* another thread between the two, then the main thread must
* block until it is time to stop. This class is a Java
* {@link java.lang.Runtime#addShutdownHook(java.lang.Thread) shutdown hook},
* returning a {@link java.util.concurrent.CountDownLatch} on
* which the main thread waits. This latch is decremented when
* the Java {@code Runtime} executes the shutdown hook. Since the
* latch is size one, {@link CountDownLatch#await()} will return.
*
* This returned latch may be passed to other objects which can
* decrement the latch and so signal that the application is to
* terminate.
*
*
* An example Java main method uses this class as follows:
*
*
*
* import java.util.concurrent.CountDownLatch;
*
* public static void main(final String args[])
* {
* // 1. Check the command line arguments.
* // 2. Initialize the application.
* // 3. Set up the shutdown hook.
* final CountDownLatch signal = ShutdownHook.addShutdownHook();
*
* // 4. Start application thread.
* // 5. Wait for the JVM to stop.
* try {
* signal.await();
* } catch (InterruptedException interrupt) {}
*
* // 6. Tear down the application.
* }
*
*
*
* @author Charles Rapp
*/
public final class ShutdownHook
extends Thread
{
//---------------------------------------------------------------
// Member data.
//
//-----------------------------------------------------------
// Statics.
//
/**
* The singleton shutdown hook instance.
*/
private static ShutdownHook sInstance = null;
/**
* The lock protecting access to {@link #sInstance}.
*/
private static final Lock sLock = new ReentrantLock();
//-----------------------------------------------------------
// Locals.
//
/**
* When the JVM is shutting down, decrement this signal.
*/
private final CountDownLatch mSignal;
//---------------------------------------------------------------
// Member methods.
//
//-----------------------------------------------------------
// Constructors.
//
/**
* Creates a new JVM shutdown hook using the given signal.
* @param signal when the JVM is shutting down, decrement
* this signal.
*/
private ShutdownHook(final CountDownLatch signal)
{
mSignal = signal;
} // end of ShutdownHook(CountDownLatch)
//
// end of Constructors.
//-----------------------------------------------------------
//-----------------------------------------------------------
// Thread Method Overrides.
//
/**
* Decrements the signal which results in a return from
* {@link CountDownLatch#await()}.
*/
@Override
public void run()
{
mSignal.countDown();
} // end of run()
//
// end of Thread Method Overrides.
//-----------------------------------------------------------
/**
* Returns the signal used by the shutdown hook to notify
* the caller when the JVM is shutdown. If the shutdown hook
* does not exist, then creates it and adds it to the
* default system runtime. The count down latch size is one,
* which means that {@link CountDownLatch#await()} returns
* as soon as this latch is decremented.
* @return the shutdown hook signal.
*/
public static CountDownLatch addShutdownHook()
{
CountDownLatch retval;
sLock.lock();
try
{
if (sInstance != null)
{
retval = sInstance.mSignal;
}
else
{
retval = new CountDownLatch(1);
sInstance = new ShutdownHook(retval);
(Runtime.getRuntime()).addShutdownHook(
sInstance);
}
}
finally
{
sLock.unlock();
}
return (retval);
} // end of addShutdownHook()
/**
* Unhooks the shutdown hook instance from the system
* runtime.
*/
public static void removeShutdownHook()
{
sLock.lock();
try
{
if (sInstance != null)
{
(Runtime.getRuntime()).removeShutdownHook(
sInstance);
sInstance = null;
}
}
finally
{
sLock.unlock();
}
} // end of removeShutdownHook()
} // end of class ShutdownHook