I have a Console-Java game. The score from the game will be saved in a JSON file if Ctrl+C is pressed. The process to save the score in a JSON file works. But I don't know, how to detect Ctrl+C from the console and if this happens, I will save the score (just a method call).
With KeyListener it doesn't work on the console (only with JFrame as far as I know).
I couldn't find a solution to my problem on the internet.
Do I have to do it with Runtime? I have tried it, but it didn't work...
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
Test.mainThread.interrupt();
}
});
There are similar questions on Stackoverflow, but not for use on the console Catching Ctrl+C in Java
Adding a shutdown hook is the right way to do it, but Test.mainThread.interrupt(); probably will not work. The JVM is already shutting down. Your mainThread is unlikely to have time to respond to an interrupt; once all shutdown hooks finish, Java terminates.
Just have your shutdown hook explicitly perform whatever actions you need taken:
Runtime.getRuntime().addShutdownHook(new Thread()
{
#Override
public void run()
{
try
{
Test.saveScore();
}
catch (IOException e)
{
System.err.println("Couldn't save score before terminating.");
e.printStackTrace();
}
}
});
We know that CTRL-C closes the application and shuts down the JVM. And since it is a normal shutdown, it runs the shutdown hooks. So creating a shutdown hook is a correct approach:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// Do something to save the score
}));
Note that we're passing a Runnable here as the shutdown task. So we can pass an object that has the required functionality:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
gameScores.save(); // assuming we have a gameScores object in this scope
}));
Your initial attempt by interrupting the thread can be viewed as a variant of this approach. Instead of passing the business object - gameScores - we can pass the thread to interrupt it later. But it's better to operate on the business level.
Related
I am working on an application that needs to launch a process and wait for its output. Sometimes the process crashes (very often,) but is not really an issue since I have mitigation tasks. The problem is that Windows detects the process crashed and prompts for user input, to either check for a solution online, or just close the program.
I tried to solve this by waiting for the process to complete in a Runnable submitted to an ExecutorService and using the Future returned to specify a timeout. Speed is not really a concern for the application, and the external process is supposed to run for just a couple of seconds.
This is the code I am using:
final Process process = ...
final ExecutorService service = Executors.newSingleThreadExecutor();
try {
final Future<?> future = service.submit(new Runnable() {
#Override
public void run() {
try {
process.waitFor();
} catch (InterruptedException e) { /* error handling */}
}
});
future.get(10, TimeUnit.SECONDS);
} catch (final TimeoutException e) {
// The process may have crashed
process.destroy();
} catch (final Exception e) {
// error handling
} finally {
service.shutdown();
}
The code above worked well, but the crash dialog still pops up and it doesn't go away without user interaction.
This question presents a similar problem but from a .Net perspective and
proposes to suppress the pop up through the Windows registry, which I cannot do, given that its effect is global to all process in the machine.
Is there a way to prevent the dialog from being displayed at all?
or
Is there a way to detect the application crash and handle it directly
from Java without needing user interaction?
Additional details:
I don't have the source of the external process.
The external process is a console based application (i.e. no GUI.)
Preferably I'm looking for a pure Java based solution (no JNI.)
Thank you.
As already suggested you should use SetErrorMode win32 call. It won't change for the whole system but only for your process and it's children (which is what you want apparently).
The correct call seems to be :
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
See also the MSDN documentation :
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621%28v=vs.85%29.aspx
Regards.
I am trying to get a shutdown hook to work on my ubuntu server, however I seem to have an issue with more than one thread. Using the a basic ShutdownHook, the following bit of code does work when I kill the process using kill <PID>, meaning the shutdown behavior is activated.
public static void main(String[] args) {
ShutdownHook shutDown = new ShutdownHook();
shutDown.attachShutDownHook();
while(true){}
}
however this same code with an additional thread does not
public static void main(String[] args) {
ShutdownHook shutDown = new ShutdownHook();
shutDown.attachShutDownHook();
(new Thread() {
public void run() {
while ( true ) {}
}
}).start();
while(true){}
}
Any ideas?
class ShutdownHook {
ShutdownHook() {
}
public void attachShutDownHook() {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
System.out.println("Shut down hook activating");
}
});
System.out.println("Shut Down Hook Attached.");
}
}
The JVM won't exit while there are still non-daemon threads running. Try calling setDaemon(true) on your new thread.
To take an example from a project of my own;
My core class spawns a whole bunch of worker threads, the workers run transactions that must complete.
In the core class I have;
Runtime.getRuntime().addShutdownHook(new ShutdownCleanup());
Which looks something like;
public final class ShutdownCleanup extends Thread() {
public void run() {
log("waiting for worker threads to finish...");
while(WorkerThread.transactionInProgress()) {
Thread.sleep(1000);
}
//close various sockets and resources
}
}
The moment I hit Ctrl+C in the terminal, the log message appears. So the shutdown hook activates immediately, it isn't something that runs once the program is ready to die, rather it runs as soon as the close or kill request is received.
For this reason I believe what others have said about shutdown hooks never being called while there is still a thread alive is false. What would be the point of a shutdown hook that only activated once everything has died anyway?
It might be that you're using a hard kill, such as -9. Have you tried a normal shutdown with Ctrl+C or SIGINT?
java.lang.Runtime.addShutdownHook( Thread ) registers a new virtual-machine shutdown hook:
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.
Your code runs indefinitely so the shutdown hook will never be called.
[After your edit]
Which kill do you use?
kill -9 is non trappable
kill -2 may be used to emulate a ctrl-c (SIGINT)
I was going through shutdown hook feature of java , My analysis was ..shutdownhook allows to register a thread that will be created immediatly but started only when the JVM ends ! So it is some kind of "global jvm finalizer", and you can make useful stuff in this thread (for example shutting down java ressources like an embedded hsqldb server). This works with System.exit(), or with CTRL-C / kill -15 (but not with kill -9 on unix, of course).
Please advise more practical uses and please also if possibe an small example will help to make understanding more clear..!
When a shutdown hook is added to a Runtime instance, it is added to a list of Threads to start upon clean termination of the JVM.
Example: Using shutdown hook to ensure that a java.awt.TrayIcon is removed from the system tray.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
if (SystemTray.isSupported()) {
SystemTray.getSystemTray().remove(yourTrayIcon);
}
} catch (Exception e) {
// failed to remove
e.printStackTrace();
}
}
});
More can be read in the offical documentation.
I have a requirement, that I want to start a poller once which will run foreever until the machine is restarted or the process is being killed. Now, I tried to start the poller from a main method using a shell script, but the problem is that as soon as the main method completed its execution, the poller also stoped working, as i am not using any servers to achieve so.
I heard something about daemon threads, but I am wondering how to create a daemon thread, which will run forever, and help my poller to run also.
UPDATE:
public class SomeThread extends Thread {
#Override
public void run() {
UnitPoller unitPoller = new UnitPoller();
unitPoller.doPolling();
}
public static void main(String[] args) {
SomeThread someThread = new SomeThread();
someThread.setDaemon(true);
someThread.start();
}
}
Above is my updated class, now whenever I execute this thread from the main method, it creates a thread but as soon as the execution of main method completes, my poller stops working, as the JVM shuts down.
With this problem, what should i do.
Thanks
You just create a thread and call th.setDaemon(true) before calling th.start().
Edit:
The above answers the question "how to create a daemon thread", but (as the scope of the question has changed), a proper answer would be: don't create a daemon thread if you want your thread to keep the JVM from exiting once the main thread completed.
1) You need someThread.setDaemon(false) instead of 'true'. A daemon thread actualy does NOT stop java from shutting down.
From the javadoc:
void java.lang.Thread.setDaemon(boolean on)
Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads.
This method must be called before the thread is started.
2) I think it's not your main, but your run() method that finishes to soon. Try to put a while (true) loop around your doPolling method.
#Override
public void run() {
UnitPoller unitPoller = new UnitPoller();
while (true)
unitPoller.doPolling();
}
3) It's cleaner to call join() inside the main then to rely on daemon thread behavior.
try {
someThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
4) If you need a clean way to shut down the deamonthread. Consider implementing InterruptedException to exit the polling task. You can also use the shutdown hook.
The term "daemon thread" in Java is a bit misleading, as it really means "that thread is not supposed to keep the JVM alive". This means that the JVM will shut down as soon as the last non-daemon thread terminated (as you already stated in your question).
What you are possibly looking for is the Apache Commons Daemon project, which allows to create nice "system services", started through /etc/init.d/ entries and all. This works on Windows and *nix systems.
I have made a java application and have packed it into an executable jar file. Now a user can start that program from either of the following two ways:
Start if from command prompt by executing the following command on the command prompt:
java -jar "MyJar.jar"
By double clicking on that jar file.
I want that my client would adopt second approach as it is much easier than the first approach. But the problem with second approach is how to stop application before it has finished?
It is a command-line application.
And no command prompt window appears when a user double clicks on the jar file. So in this case, Will Ctrl + c work?
Stopping (exiting) the application should be inside the application. Whether it is command line or GUI based, the application developer should write code to exit it (For eg., in a command line application you might have something like Press 5 to exit, Press Esc to Exit etc) and in an application with a GUI, you will have to write code to exit when the window is closed, or an EXIT button (or others, depending on your application)
Ctrl + C is KILL the application. This is not a Normal exit. For apps with a GUI, the user would typically (in Windows) go to task manager and end the process (similar ways in other operating systems)
But these are abnormal exits - when the user wants to kill the app when, for instance, the application is no longer responding. Normal exits should be provided by the application (and therefore by the programmer - you)
I've had a similar problem. I have some Java programs that are basically long-running daemon processes. It's nice to be able to stop them and bounce (restart) them.
I've used two approaches. Both have advantages and disadvantages. One is to set up a signal handler, by putting a function like this in some class of your program (in mine, it's in the class with the main method).
import sun.misc.Signal;
import sun.misc.SignalHandler;
...
private static boolean stopNow = false;
private static boolean restartNow = false;
...
private static void handleSignals() {
try {
Signal.handle(new Signal("TERM"), new SignalHandler() {
// Signal handler method for CTRL-C and simple kill command.
public void handle(Signal signal) {
MyClass.stopNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.warn("No SIGTERM handling in this instance.");
}
try {
Signal.handle(new Signal("INT"), new SignalHandler() {
// Signal handler method for kill -INT command
public void handle(Signal signal) {
MyClass.stopNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.debug("No SIGINT handling in this instance.");
}
try {
Signal.handle(new Signal("HUP"), new SignalHandler() {
// Signal handler method for kill -HUP command
public void handle(Signal signal) {
MyClass.restartNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.warn("No SIGHUP handling in this instance.");
}
}
This has worked robustly for us in production. You need a genuine Sun JRE for this to work; the one shipped with a typical Linux distro doesn't have the Signal stuff in it. It works OK on Windows too, but you don't get the HUP signal. You do need a shortcut or shellscript to launch this thing.
Also, keep in mind that signal handling is a big fat botch. Don't try to do very much inside your signal handler. You can see that my sample code simply sets static flags. Other parts of my program detect that the flag changed, and shut down. I could have experimented with more complex code inside the signal handler, but I didn't feel like taking on the QA burden.
The other approach is to structure your program as a Servlet. You'll write a class that extends HttpServlet in this case. Override Servlet.init with a method that starts your worker thread. Likewise, Override Servlet.destroy with a method that shuts yourself down.
Then you can use a Java EE container server like Tomcat to manage your starting and stopping.
If your program is a console mode program and it's doing output, Ctrl-C should be able to kill it.
If it's a GUI program, you'll want to give it a button to exit, or at least setting EXIT_ON_CLOSE as the defaultCloseOperation of your main JFrame.
ctrl+alt+suppr -> kill the javaw.exe ? :p
Or you would have to present a user interface with a stop button (see swing etc)
It depends on the User Interface. If its a Swing application then you can setDefaulCloseOperation(JFrame.EXIT_ON_CLOSE) on your main Frame. If its a console app and the user is interacting with it then you ask the user to enter a value that indicates to you that they want to stop the app. If yoy are not interacting with the user at all then ctrl-c will have to work.
Is it a GUI application or commandline.
In first case just handle the window closing event. In second case handle e.g. CTRL + C
that depends on what kind of application is it?
Is it a swing application? If so, then your app should handle when user clicks the 'close' button. There is a behavior for that. JFrame.close()
If it isnt a swing app then ctrl+c will work.
"It is a command-line application" you say.. Well you could do it so that when the user hit a button (say esc) he can write short commands to exit, restart etc..
You can do this with KeyListener. When ESC is hit (say that is the button you want the user to hit), you use Scanner on System.in, and you will do a System.exit(0); if the input is "exit".
I've used socket connection to enable kill of running instance.
//send kill signal to running instance, if any
try {
new Socket("localhost", 4000).getInputStream().read(); //block until its done
} catch (Exception e) { //if no one is listening, we're the only instance
}
//start kill listener for self
new Thread() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(4000);
serverSocket.accept();
//do cleanup here
serverSocket.close();
} catch (Exception e) {
}
System.exit(0);
}
}.start();
You can use this one: exit()
It's possible to predefine all the action before virtual machine is totally stoppeed thus you can save your data and performa all actions to prevent the data loss.
I'm not sure it's a good way, because I've just started Java study, but it seems working.