Skip to content

Latest commit

 

History

History
103 lines (79 loc) · 4.13 KB

README.md

File metadata and controls

103 lines (79 loc) · 4.13 KB

java-processes

This is a small library to help you create and (automatically kill) Java processes from within Java. This is useful in a number of situations:

  • Some part of your program needs different JVM args, a different classpath, or even a different JVM.
  • You want to safely execute code that may run out of memory.
  • You want to execute multiple instances of legacy code with global state in parallel.

To start part of your Java program in a separate JVM, simply write:

Process proc = new JavaProcessBuilder(SomeClass.class, "some", "args").start();

That's it! This snippet will start a new JVM with SomeClass as the main class, passing "some" and "args" as arguments. No need to specify the classpath, the VM args, or the path to the Java executable; these are all taken from the JVM in which your program is running!

Configuration

JavaProcessBuilder makes it very simple to configure the classpath, the VM args, or the Java executable, if you want them to be different from those of the parent JVM:

Process proc = new JavaProcessBuilder(SomeClass.class)
        .javaHome("/different/java/")
        .classpath("some-classes.jar")
        .vmArgs("-ea", "-Xmx8g")
        .start();

If you know the ProcessBuilder class from the Java Standard Library, you may also know that lets you specify a number of additional options when starting a process, such as environment variables, working directory, or I/O behavior. JavaProcessBuilder is actually built on top of ProcessBuilder, so you can configure all of these things too:

Process proc = new JavaProcessBuilder(SomeClass.class)
        .classpath("some-classes.jar")
        .build()
        .directory(new File("test"))
        .inheritIO()
        .start();

What is happening here is that build() returns a ProcessBuilder instance that has all the JVM-specific configuration imprinted and can then be further configured. In fact, the JavaProcessBuilder.start() method is simply a shorthand for build().start().

Automatically Killing Child Processes

One thing that is annoying when executing parts of your program in separate JVMs is that they continue to run when you kill the parent process (especially during debugging). This library comes with two mechanism that can help you with that.

AutoProcessKiller

The first mechanism is based on shutdown hooks and can be used in the following way:

new AutoProcessKiller().add(process);

Now, when the JVM shuts down, the AutoProcessKiller (which is a Thread) is executed and kills the process (if it is still running). However, this will not work if the JVM is terminated forcibly, which happens, for example, if you press the stop button in Eclipse. In this case, the shutdown hooks may not be executed, so the child processes may continue to run. In fact, I think any mechanism to kill child processes from within the parent JVM is doomed to suffer from this problem.

AutoExit

This is why this library comes with a second mechanism, which works from within the child VM and is guaranteed to kill the child process as soon as the parent process stops running (for whatever reason). You can use it by calling

AutoExit.install();

in the child VM. Or, to make it even simpler, you can call autoExit(true) on the process builder instance that you use to start the child VM:

Process proc = new JavaProcessBuilder(SomeClass.class).autoExit(true).start();

In this case, the process builder will use the AutoExitProgram class as the actual main class, which in turn calls AutoExit.install() and then calls SomeClass.main().

This mechanism is based on a simple trick: AutoExit (being a separate thread) calls System.in.read(), which only returns once the parent process terminates. As soon as this happens, System.exit() is called. Note, however, that this trick does not work if you need to use System.in for something else in the child process. In that case, you should use the first mechanism.