how can I kill a Linux process in java with SIGKILL Process.destroy() does SIGTERM
Not using pure Java.
Your simplest alternative is to use Runtime.exec()
to run a kill -9 <pid>
command as an external process.
Unfortunately, it is not that simple to get hold of the PID. You will either need to use reflection black-magic to access the private int pid
field, or mess around with the output from the ps
command.
UPDATE - actually, there is another way. Create a little utility (C program, shell script, whatever) that will run the real external application. Code the utility so that it remembers the PID of the child process, and sets up a signal handler for SIGTERM that will SIGKILL the child process.
Program a unix kill in Java
In short, no, there isn't.
On a unix system, the best bet is to use Runtime.exec().
kill process using sigterm and escalate to sigkill after timeout
There's the timeout
command, which allows you to cap a process' execution time and escalate to a SIGKILL if it doesn't respond promptly to the initial signal (SIGTERM by default). This isn't quite what you're asking for, but it might be sufficient.
To do what you're actually describing (send a signal, briefly await, then send a kill) you may have to do a bit of bookkeeping yourself, as this question details.
One option would be to use Upstart (or I imagine other service managers), which provides a kill timeout n
command that does what you want.
As an aside, many systems would treat 30 minutes as much too long to wait for SIGTERM. Linux does something akin to what you're describing on shutdown, for instance, but gives processes barely a few seconds to clean up and exit before SIGKILLing them. For other use cases you certainly can have a long-lived termination like you describe (e.g. with Upstart), but YMMV.
Killing a Java Process object
The solution in my case, since I was writing both the parent and the child processes, was to add a ShutdownHook which halted the JVM (a simple System.exit(1) was not sufficient):
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
Runtime.getRuntime().halt(5);
}
});
After this, when a SIGTERM was received the process would terminate, as though it had been sent SIGKILL by the parent process.
How to gracefully handle the SIGKILL signal in Java
It is impossible for any program, in any language, to handle a SIGKILL. This is so it is always possible to terminate a program, even if the program is buggy or malicious. But SIGKILL is not the only means for terminating a program. The other is to use a SIGTERM. Programs can handle that signal. The program should handle the signal by doing a controlled, but rapid, shutdown. When a computer shuts down, the final stage of the shutdown process sends every remaining process a SIGTERM, gives those processes a few seconds grace, then sends them a SIGKILL.
The way to handle this for anything other than kill -9
would be to register a shutdown hook. If you can use (SIGTERM) kill -15
the shutdown hook will work. (SIGINT) kill -2
DOES cause the program to gracefully exit and run the shutdown hooks.
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.
I tried the following test program on OSX 10.6.3 and on kill -9
it did NOT run the shutdown hook, as expected. On a kill -15
it DOES run the shutdown hook every time.
public class TestShutdownHook
{
public static void main(String[] args) throws InterruptedException
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run()
{
System.out.println("Shutdown hook ran!");
}
});
while (true)
{
Thread.sleep(1000);
}
}
}
There isn't any way to really gracefully handle a kill -9
in any program.
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 only real option to handle a kill -9
is to have another watcher program watch for your main program to go away or use a wrapper script. You could do with this with a shell script that polled the ps
command looking for your program in the list and act accordingly when it disappeared.
#!/usr/bin/env bash
java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"
How to send SIGINT signal from Java to an external process?
Are you running the external program as a java.lang.Process
? As the Process class has a destroy()
method.
How to stop a command being executed after 4-5 seconds through process builder?
As I understand it you want to stop a subprocess if it runs longer than four or five seconds. This cannot be done directly with ProcessBuilder
(you can see that no relevant method exists in the class), but you can implement this behavior easily enough once the subprocess has begun.
Calling Process.waitFor()
as you do in your sample code is problematic because it will block your current thread indefinitely - if your process takes longer than five seconds .waitFor()
will not stop it. However .waitFor()
is overloaded and its sibling takes a timeout
argument.
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException
Causes the current thread to wait, if necessary, until the subprocess represented by this Process object has terminated, or the specified waiting time elapses.
You can use this in tandem with Process.destroy()
to stop the process if it takes too long. For example:
Process process = new ProcessBuilder(command, and, arguments)
.redirectErrorStream(true)
.directory(workingDir)
.start();
process.waitFor(5, TimeUnit.SECONDS);
process.destroy();
process.waitFor(); // wait for the process to terminate
This relies on the fact that Process.destroy()
is a no-op when called on an already-finished subprocess. Before Java 9 this behavior was not documented, but in practice has always been the case. The alternative would be to inspect the return value of .waitFor()
, but this would introduce a TOCTTOU race.
What about Process.destroyForcibly()
? Generally speaking you should not call this method (another thing the JDK could be clearer about), however if a process is truly hung it may become necessary. Ideally you should ensure your subprocesses are well-behaved, but if you must use .destroyForcibly()
this is how I would recommend doing so:
// Option 2
process.waitFor(5, TimeUnit.SECONDS); // let the process run for 5 seconds
process.destroy(); // tell the process to stop
process.waitFor(10, TimeUnit.SECONDS); // give it a chance to stop
process.destroyForcibly(); // tell the OS to kill the process
process.waitFor(); // the process is now dead
This ensures that misbehaving processes will be killed promptly, while still giving properly implemented programs time to exit upon being instructed. The exact behavior of .destroy()
and .destroyForcibly()
is OS-specific, but on Linux we can see that they correspond to SIGTERM
and SIGKILL
:
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
kill(pid, sig);
You should rarely have a need to call .destroyForcibly()
, and I would suggest only adding it if you discover it is necessary.
Option 2 is conceptually similar to using the timeout
command like so:
$ timeout --kill-after=10 5 your_command
It's easy enough to replicate Process.waitFor(long, TimeUnit)
in Java 7, there's nothing magic about the default Java 8 implementation:
public boolean waitFor(long timeout, TimeUnit unit)
throws InterruptedException
{
long startTime = System.nanoTime();
long rem = unit.toNanos(timeout);
do {
try {
exitValue();
return true;
} catch(IllegalThreadStateException ex) {
if (rem > 0)
Thread.sleep(
Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
}
rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
} while (rem > 0);
return false;
}
Related Topics
Connection Pooling Options With Jdbc: Dbcp VS C3P0
How to Sort Map Values by Key in Java
Java: How to Get a Class Literal from a Generic Type
How to List Target Platforms. Please Make Sure the Android Sdk Path Is Correct
How to Connect Remote MySQL Database in Android Using Jdbc
How to Return an Array from Jni to Java
Understand the R Class in Android
Java Jsch Changing User on Remote MAChine and Execute Command
Javafx: Could Not Find or Load Main Class Only on Linux
How to Run Sudo Command Without Password from Java Program
Kafka - Broker: Group Coordinator Not Available
Find Native Memory Leak in Java Application Using Jemalloc
Issues with Corba Communication
Eclipse Swt Browser Crash (Linux 64Bit)
Jaspersoft Studio 6.2 Build Path Warning