There is a console Java application which is supposed to run until it is stopped by Ctrl+C or closing the console window. How that application can be programmed to execute a clean up code before exit?
You could use a Shutdown Hook.
Basically you need to create a Thread which will perform your shutdown actions, and then add it as a shutdown hook. For example:
class ShutdownHook extends Thread
{
public void run()
{
// perform shutdown actions
}
}
// Then, somewhere in your code
Runtime.getRuntime().addShutdownHook(new ShutdownHook())
A Shutdown hook is the way to go, but be aware that there is no guarantee that the code is actually executed. JVM crashes, power failures, or a simple "kill -9" on your JVM can prevent the code from cleaning up. Therefore you must ensure that your program stays in a consistent state even if it has been aborted abruptly.
Personally, I simply use a database for all state-storage. Its transactions model makes sure that the persistent storage is in a sane state no matter what happens. They spend years making that code fool-proof, so why should I waste my time on problems already solved.
Program to delete temp file bat.bat when program is exited:
public class Backup {
public static void createBackup(String s)
{
try{
String fileName ="C:\\bat"+ ".bat";
FileWriter writer=new FileWriter(fileName);
String batquery="cd C:\\Program Files\\MySQL\\MySQL Server 5.0\\bin"
+ "\nmysqldump -uroot -proot bankdb > \""+s+".sql\""
+"\nexit";
writer.append(batquery);
writer.close();
}
catch(Exception e){e.getMessage();}
try{
Process p =Runtime.getRuntime().exec("cmd /c start C:\\bat.bat");
}
catch(Exception e){e.getMessage();}
ShutDownHook sdh=new ShutDownHook();
Runtime.getRuntime().addShutdownHook(sdh);
}
}
class ShutDownHook extends Thread
{
public void run()
{
try
{
File f=new File("c:/bat.bat");
f.delete();
}
catch(Exception e){e.getMessage();}
}
}
The code written inside a Threads run() method will execute when the runtime object terminates...
class ShutdownHookclass extends Thread {
public void run() {
// perform shutdown actions
}
}
//could be written anywhere in your code
Runtime.getRuntime().addShutdownHook(new ShutdownHookclass())
Related
I am writing a program where i am creating multiple threads in a process.
I need to handle that if the process is killed externally by someone by using kill -9 signal or Ctrl + C, my program should do some action before closing e.g. it should change the status of process to aborted in database.
How can i handle that ?
Do i need addShutdownHook() ? or is there any other better solution to my problem ?
I have added :
Runtime.getRuntime().addShutdownHook( new Thread() {
#Override
public void run() {
logger.info( "Running Shutdown Hook" );
//call some method
System.out.println( "Running Shutdown Hook" );
}
} );
inside my main method, But it doesn't seem to work.
Short answer: probably won't work.
See JavaDoc for that addShutdownHook():
In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows... If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.
In other words: a shutdown hook is not a robust choice to address your requirements.
Did you put it in a place where it would be instantiated? Try running the following and killing it
import java.util.concurrent.TimeUnit;
public class KillTest {
public static void main(String args[]) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
call some method
System.out.println("Running Shutdown Hook");
}
});
try{
TimeUnit.MINUTES.sleep(10);
}catch(Exception e){
System.out.println("Error thrown");
}finally {
System.out.println("How awesome is finally?");
}
}
}
If i have gotten it correctly each java process is associated with a separate instance of JVM and each instance of JVM is provided with a Heap memory by the OS which is also recollected by the OS on JVM termination. So on termination even if there were some memory leaks all the memory will be reclaimed by the OS(Please correct if I have mistaken).
In case point number 1 is true why do we have to use shutdown hooks. After googling everything mainly suggests to free all the resources and graceful shutdown. Even if it does not gracefully shutdown all the memory and resources would be freed?
I wrote a simple shutdown hook. In my main thread I am running an infinite loop and then terminating the process using terminate button in Eclipse. But the shutdown hook thread is not running.
Does terminating process in eclipse call Runtime.getRuntime().halt(status) because AFAIK that terminated JVM abruptly and not execute shutdown hook?
Lastly if I have my main code something like below -
public static void main(String args[]){
Runtime.getRuntime().addShutdownHook(new Thread(new ShutDownHook()));
System.out.println("Shutdown hook registered");
System.out.println("Before calling exit");
System.exit(0);
System.out.println("After exit");
}
why is After exit not printed? When shutdown hook is in execution main thread must continue further execution and print After exit?
1) You are correct.
2) The Java process' memory will be reclaimed, but you might want to do other cleanup, like delete some temp files.
3) Let's go to the javadoc of Runtime#addShutdownHook(Thread)
The Java virtual machine shuts down in response to two kinds of
events:
The program exits normally, when the last non-daemon thread exits or
when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt,
such as typing ^C, or a system-wide event, such as user logoff or
system shutdown.
You would have to look into Eclipse's source code, but it would seem like Eclipse terminates the process rather than sending a System.exit(..) or a sending a user interrupt. This probably goes over the JVM which therefore doesn't execute the shutdown hooks.
4) The shutdown hooks you add with Runtime#addShutdownHook(Thread) are added to a static IdentityHashMap in the ApplicationShutdownHooks. This class registers its own shutdown hook with the Shutdown class in a static initializer block shown below
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;
}
}
The runHooks() method is
static void runHooks() {
Collection<Thread> threads;
synchronized(ApplicationShutdownHooks.class) {
threads = hooks.keySet();
hooks = null;
}
for (Thread hook : threads) {
hook.start();
}
for (Thread hook : threads) {
try {
hook.join();
} catch (InterruptedException x) { }
}
}
So the current thread joins all the other ones.
When
System.exit(0);
gets called, somewhere down the line Shutdown.sequence() gets called which invokes Shutdown.hooks() implemented as
private static void runHooks() {
for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
try {
Runnable hook;
synchronized (lock) {
// acquire the lock to make sure the hook registered during
// shutdown is visible here.
currentRunningHook = i;
hook = hooks[i];
}
if (hook != null) hook.run();
} catch(Throwable t) {
if (t instanceof ThreadDeath) {
ThreadDeath td = (ThreadDeath)t;
throw td;
}
}
}
}
One of the Runnable objects in hooks is what I described above. It doesn't spawn a new Thread, it does it concurrently with run().
Once Shutdown.sequence() is done, the system really exits, so the final System.out.println() doesn't execute.
I have created a Java GUI application which functions as a wrapper for many low level external processes. The utility works as is, but is in desperate need of one major improvement.
I want my external process run in a non-blocking manner which would permit me to service additional requests in parallel. In a nutshell I want to be able to process data from the external process as the data is being generated. But it appears my basic attempt to check and see if the external process is still running is blocking.
Below is an excerpt from my ExternalProcess class. Please see inline comments for specific Java functionality questions about threading and blocking.
public void Execute()
{
System.out.println("Starting thread ...\n");
Runner = new Thread(this, "ExternalProcessTest");
Runner.run();
System.out.println("Ending thread ...\n");
}
public void run()
{
System.out.println("In run method ...\n"); // Debug purposes only.
// Show that we are in the run loop.
try
{
// Execute string command SomeCommand as background process ...
Process = Runtime.getRuntime().exec(SomeCommand);
while(IsRunning())
{
// External process generates file IO. I want to process these
// files inside this loop. For the purpose of this demo I have
// removed all file processing to eliminate it as the cause
// of blocking. THIS ROUTINE STILL BLOCKS!
Thread.sleep(1000);
}
}
catch(Exception e)
{
System.out.println(e);
}
System.out.println("Exiting run method ...\n"); // Debug purposes only.
// Show that we are exiting the run loop.
}
// Process (instantiated from Runtime.getRuntime().execute doesn't supports
// either fire-and-forget backgrounding (non-blocking) or you can wait for
// the process to finish using the waitFor() method (blocking). I want to
// be able to execute a non-blocking external process that I monitor via
// threading allowing me to process the external process file IO as it is
// created. To facilitate this goal, I have created an isRunning() method
// that uses the exitValue() method. If the process is still running, a
// call to exitValue() will throw an IllegalThreadStateException exception.
// So I simply catch this execption to test if the background process is
// finished -- at which point I can stop processing file IO from the
// process. Is this the source of the blocking? If so, is there another
// way to do this?
public boolean IsRunning()
{
boolean isRunning = false;
try
{
int exitVal = Process.exitValue();
}
catch(IllegalThreadStateException e)
{
isRunning = true;
}
return isRunning;
}
The run() method on Thread doesn't actually start a new thread, try using Thread.start() instead.
Runner = new Thread(this, "ExternalProcessTest");
Runner.run();
The run() method is deceptively named. Because Thread implements the Runnable interface the run() method is exposed publicly, but it is not the right method to call when you want to kick off a new thread. Calling run() causes the thread code to be run in the current thread.
You must call start() to cause a new thread to be instantiated:
Runner = new Thread(this, "ExternalProcessTest");
Runner.start();
My Goal
I am attempting to make a Java program in which a user can select any .class or .jar file from their computer. My program will then pop up a JInternalFrame with a JEditorPane in it as the console, capturing any console output from the user's program. When the user's program closes (calls System.exit(int status);), my program must not close along with it. My program might also have such features as a button to immediately stop the user's program and others an IDE would. My program need not compile Java code, only run .class and .jar files.
My Experience
I have made a small test version of this program wherein I got two specific files from a package and had the user click one of two buttons, each representing one of the two programs. A press of a button calls the following method:
private void run(Class runnable)
{
java.lang.reflect.Method[] m = runnable.getMethods();
boolean hasMain = false;
for (int i = 0; i < m.length; i++)
{
if (m[i].getName().equals("main") && m[i].getParameterTypes()[0].isArray() && m[i].getParameterTypes()[0].getName().contains("java.lang.String"))
try
{
Object invoke = m[i].invoke(null, (Object)globalArgs);
hasMain = true;
hub.setExtendedState(Hub.ICONIFIED);
numPrograms++;
}
catch (Throwable t)
{
java.util.logging.Logger.getLogger(Hub.class.getName()).log(java.util.logging.Level.SEVERE, null, t);
javax.swing.JOptionPane.showMessageDialog(null, "Could not run " + runnable.getName(), "Error in invocation", javax.swing.JOptionPane.ERROR_MESSAGE);
}
finally
{
break;
}
}
if (!hasMain)
javax.swing.JOptionPane.showMessageDialog(null, runnable.getName()
+ " does not have a public static main method that\nreturns void and takes in an array of Strings",
"No main method", javax.swing.JOptionPane.ERROR_MESSAGE);
}
This method successfully calls either program's main method and runs a copy of said program. However, when any of the programs this hub has started calls the System.exit(int status) command, the hub closes, too. Also, I haven't the slightest clue as to how to capture console output.
My Questions
Does anyone have any experience or advice they would be willing to share to help me make a fully-functional program that can...
Open and run a compiled Java file (remember that .jar files may have more than one class with main(String[] args) method)
Catch System.exit(int status); so that the hub program handles the internal program's exiting
Catch new java.io.PrintStream().println(Object o) and similar calls and place their output in a JEditorPane
Make a button that, when pressed, stops the internal program from running
Possibly make all JFrames the internal program uses into JInternalFrames and place them in a JDesktopPane
If you don't want the other program (which you call through it's main method) to be able to shut down the JVM you're running in, you have, as I see it, three options:
1. Using a SecurityManager
Set up the SecurityManager so that it prevents the System.exit call:
public class Test {
public static void main(String args[]) {
SecurityManager sm = System.getSecurityManager();
System.setSecurityManager(new SecurityManager() {
#Override
public void checkExit(int status) {
throw new SecurityException("Client program exited.");
}
});
try {
System.out.println("hello");
System.exit(0);
System.out.println("world");
} catch (SecurityException se) {
System.out.println(se.getMessage());
}
}
}
Prints:
hello
Client program exited.
This is probably the nicest solution. This is the way application servers prevent an arbitrary servlet from terminating the entire server.
2. Separate JVM
Run the other program in a separate JVM, using for instance ProcessBuilder
import java.io.*;
public class Test {
public static void main(String args[]) throws IOException {
ProcessBuilder pb = new ProcessBuilder("java", "other.Program");
pb.redirectErrorStream();
Process p = pb.start();
InputStream is = p.getInputStream();
int ch;
while ((ch = is.read()) != -1)
System.out.print((char) ch);
is.close();
System.out.println("Client program done.");
}
}
3. Use shutdown hooks instead
Don't disallow the termination of the JVM, but instead add shutdown-hooks that cleans up the "hub" and exits gracefully. (This option probably only makes sense if your running one "external" program at a time.)
import java.io.*;
public class Test {
public static void main(String args[]) throws IOException {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Uninitializing hub...");
System.out.println("Exiting gracefully.");
}
});
// Run client program
System.out.println("Running... running... running...");
System.exit(0);
}
}
Prints:
Running... running... running...
Uninitializing hub...
Exiting gracefully.
Hi I have an Standalone application in which when an user logs in a abc.lck file gets created when the application is closed it gets deleted.I have used addshutdownhook() to delete the file when power supply is interrupted that is switching off the power supply when my application is running.My problem is the file is not getting deleted when I manually shutdown the system i.e by start-->shutdown and I should prompt the user with a message to save the changes using cofirm dailog box like in MS Word.Can some one help me
Thanking u
Chaithu
The general contract of addShutdown hook is
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
A shutdown hook 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 run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will 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 exit method.
In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the 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.
Hence during shutdown, the Windows machine may call TerminateProcess and hence your shutdown hook might not be invoked.
Use deleteOnExit method instead of adding shutdownhook. However, take a look at this sample,
class Shutdown {
private Thread thread = null;
protected boolean flag=false;
public Shutdown() {
thread = new Thread("Sample thread") {
public void run() {
while (!flag) {
System.out.println("Sample thread");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException ie) {
break;
}
}
System.out.println("[Sample thread] Stopped");
}
};
thread.start();
}
public void stopThread() {
flag=true;
}
}
class ShutdownThread extends Thread {
private Shutdown shutdown = null;
public ShutdownThread(Shutdown shutdown) {
super();
this.shutdown = shutdown;
}
public void run() {
System.out.println("Shutdown thread");
shutdown.stopThread();
System.out.println("Shutdown completed");
}
}
public class Main {
public static void main(String [] args) {
Shutdown shutdown = new Shutdown();
try {
Runtime.getRuntime().addShutdownHook(new ShutdownThread(shutdown));
System.out.println("[Main thread] Shutdown hook added");
} catch (Throwable t) {
System.out.println("[Main thread] Could not add Shutdown hook");
}
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException ie) {}
System.exit(0);
}
}