Runtime.getRuntime().exec( "myprog.exe" );
will spawn an external process (usually a program written in some language other than
Java) that runs in parallel with the Java execution. In
W95, W98, Me, NT, W2K, XP and W2003, you must use an
explicit *.exe or *.com extension on the parameter. In
Vista
it will still work even if you leave it off. Be careful to include it, or your code
will mysteriously fail on the older operating systems.
It is also best to fully qualify executable names so that the system executable
search path is irrelevant and so you don’t pick up some stray program off the
path with the same name.
Starting with Java version
1.5,
exec has been replaced by
ProcessBuilder. start. You should likely not be using
exec for new programs. However, studying
exec is useful to understand old programs that use
exec and to understand why
ProcessBuilder is designed the way it is. They have many things in
common, especially the way command interpreters and internal commands must be
handled and they both use the same
Process class. So
read about
exec first, then enjoy the improved
ProcessBuilder.
EXEC vs Threads
There are two ways to get parallel execution, spawn a separate job with exec, or
use threads. Which is best for your problem?
Threads join the queue of processes to execute. The OS (Operating System)
schedules them on the next available CPU (Central Processing Unit)
core. So if you have 7 threads and 4 cores, you can
have 4 of those threads running fully simultaneously, not just interleaved. Your
threads compute just like independent jobs, though the OS
can do proprietary clever things to treat them differently.
When you exec/fork, you spin off a separate job than runs independently in a
separate address space. The spawner can fail and the child keeps going. The child can
be written in a different language. The child have very limited ability to
communicate with the spawner. In contrast a thread has access to the shared address
space directly which makes interthread communication much easier.
You can also use Thread pools where you logically want to have hundreds of
threads, but don’t want the overhead.
Overloaded exec
There are also many overloaded forms of
exec() including this most general one:
The second argument can be a String [] and can be used to
set environment variables. In the second case, C:\\SomeDirectory specifies a directory for the process to
start in. If, for instance, your process saves files to disk, then this form allows
you to specify which directory they will be saved in.
Command Interpreter
To run a *.BAT, *.CMD, *.html *.BTM or
URL (Uniform Resource Locator) you must invoke the command processor with these as a
parameter. These extensions are not first class executables in Windows. They are
input data for the command processor. You must also invoke the command processor when
you want to use the < > | piping options, Here’s
how, presuming you are not interested in looking at the output:
exec only understands
xxx.exe and parameters. It knows nothing about program names
without the
*.exe explicitly mentioned, | pipes, <
redirection >, % environment parameter subsitution, or
*.bat,
*.cmd or
*.html files. Further, commands such as
attrib,
cls,
copy
del,
dir,
format,
move and
rename are not
*.exe files. They are internal
commands to the command interpreter. For all those things you must spawn a command
interpreter/shell script with an explicit
*.exe extension
(at least in
W98, Me, NT, W2K, XP, W2003, Vista, W2008, W7-32, W7-64, W8-32, W8-64, W2012, W10-32 and W10-64, in other
OS
es, you need a fully qualified executable name) and pass it the name of your
executable or internal command as a parameter. Similarly in
Linux,
if you want to use any of the commands internal to the command processor that
don’t have corresponding independent excutables such as
alias, enable, export, pwd, unset, while…, you must spawn bash
or other shell and feed it commands as parameters.
There is an exception. In XP, W2003, Vista, W2008, W7-32, W7-64, W8-32, W8-64, W2012, W10-32 and W10-64
you can invoke a bat file so long as you use the explicit .bat extension, without resorting to a command interpreter.
Simplifications
There is also Marty Hall’s Exec class, which simplifies the process of using exec and tends to make the command more stable. Currently, only the
exec(String cmd) is supported, with a workaround for exec( String cmd,
null, String dir)
Unix
For Unix/Linux you must spawn the program that can process the
script, e.g. bash. However, you can run scripts directly with exec if you do two things:
- Start the script with #!bash or whatever the
interpreter’s name is.
- Mark the script file itself with the executable attribute.
Alternatively
I suspect you will have more success if you pass the entire command line as a single
parameter to the shell interpreter, at least if you have any redirection or piping.
Communicating With The Spawned Process
exec returns a Process object that you can
use to control, monitor or wait for the background process. This example shows you
how you can wait for the child, rather than letting it run asynchronously. This
example does not show the many possible other separate Threads you might use to:
- Spawn the child (and continue processing).
- Write the child’s input from System.in with Process. getOutputStream(). Note the stream is named
relative to the parent, not the child.
- Read the child’s output from System.out with Process. getInputStream(). Note the stream is named
relative to the parent, not the child. You must do this if there
are more that a few line of output, or the child will stall, constipated with
unread output.
- Read the child’s output from System.
err with Process. getErrorStream().
- One each to read the child’s output from files, sockets etc.
- Wait for the child with Process.waitFor
() once you have all the hooks set up.
- Timer to kill the child and interrupt the
waitFor() thread with
Thread.interrupt() if the child
takes too long.
You need to start all these possible Threads after
you create the Process object, but before you call
waitfor.
Process.getOutputStream lets you write out data that
will be used as input to the process. Don’t forget to include
any \n and \r characters the process is expecting.
Process.getInputStream lets you read in the data that your
process squirted out to stdout.
The other cruder way to get the output from the execed program is to spawn a
command processor and use the > or 2> redirection operator to direct stdout or stderr to a file. When
the spawned program completes, read the file. Or simply read and write files both in
your mother and child. If batching up this way is acceptable, it is much simpler and
much less likely to go south with thread complexities.
If you wait for the Process, you might want to do it on
some thread other than the main AWT (Advanced Windowing Toolkit) event processing one, i.e.
create a new Thread, otherwise your app will not be able to process
AWT
events while you wait.
ON the Java side you may need to read and write to the child with separate threads
to avoid deadlocks. The deadlock occurs if you try to read and/or write more than a
certain amount (empirically it is around 4K). The
deadlock (a Mexican standoff freeze) happens when the child
wants you to listen when you are still trying to feed it more, or when the child is
hungry for input and you won’t send it any more until it has spoken.
Applets
You can’t use exec from
an unsigned Applet otherwise you would be able to wreck
havoc on the client machine by spawning FORMAT C:. If you
need to do that, you will need to have a signed Applet with high privilege.
If you are in an Applet and all you are trying to is
get a browser to render a page, you don’t need exec.
Simply use getAppletContext().showDocument( new URL (http://domain/file.html));
Gotchas
- If your child program produces more than a few lines of
output, your parent program must capture and process it, otherwise the child will
stall with constipation.
- The sender must use flush() to
make that data available to the receiver.
- If you are used to C exec, watch out. Java does not use
the dummy parameter 0 which duplicates the name of the program.
- In a similar way, Java main methods don’t see
that dummy parameter either.
- Your execed program will stall if it produces more than a few lines out output.
You have to make provision via the Process object for
the parent program to read the child’s System.
out and System.err output if the child produces more than a few lines.
- You must use the .exe suffix. exec is not smart enough to figure out the extension. A command
interpreter can however, figure out if you meant .bat,
.com or .exe, however. Spawn a
command interpreter instead, with the program name as a parameter. See the
example code above.
- For internal command interpreter commands like dir and
del, you must spawn a command interpreter with the command
as a parameter. You can’t spawn the command directly.
ProcessBuilder
Starting with Java version 1.5
there is a better way of handling exec called
ProcessBuilder. It has a number of advantages over
exec.
- It lets you control the environment.
- There are separate methods for setting up the various aspects of the spawn,
rather than confusing positional parameters.
- It will merge the child stderr and stdout streams for you.
Here is how
Threads to Tend the Child
Here is an example of using Threads to
communicate with the child process to feed it input and read its output. This example
does not show a separate System. err reader or a timeout timer, but this example should be enough to get
you started.
You need code like this, or the child will freeze, the sender unable
to empty it buffers and the receiver starved of data because the sender is still
holding onto it. Don’t be seduced by the fact code using a single thread will
often work for small amounts of data.
Here is the source code for the dummy boomerang.exe
utility I used to test the above code. I used Jet to compile in down to an
exe file.
On the C/C++
side, in your child program, you could use getc to read
the output from Java’s BufferedWriter and
putc to write the input to Java’s BufferedReader. One you have the communication working, replace the
C/ C++ I/O with
something fancier.
Keep in mind that using large buffers will delay releasing the output
to the other party until a buffer full of data has been accumulated. This can delude
you into thinking things are not working when they are just fine. You must also use
flush() to ensure the other party has access to all the
data recently written. If your child in written in Python, use the -u option to turn
off buffering. This will ensure the mother Java program sees the output of the child
as soon as possible.
Spawning java.exe
I mentioned earlier that exec is used to start non-Java apps, though in principle
you could spawn a copy of java.exe. However, there are
cleaner and faster ways to get that same effect.
Spawning javac.exe
There are a three basic techniques to
spawn a copy of the Java compiler: JavaCompiler, sun.tools.javac.Main, or spawning javac.exe with ProcessBuilder or
exec.
Java Web Start Spawning
If you have set up the association
between .jnlp to javaws.exe, you
can spawn a shell such an cmd.exe or tcc.exe with the name of the .jnlp file as the
parameter. If you have not, you must spawn javaws.exe with
the name of the .jnlp file as the parameter. The current
javaws.exe is automatically on the path, via the registry
HKEY_LOCAL_MACHINE/SYSTEM/Microsoft/Windows/CurrentVersion/App
Paths.
Desktop Spawning
In Java version 1.6 or later
there is a simplified exec technique. You cannot communicate with the child task.
- Desktop.open
will launch the appropriate application to handle the given file.
- Desktop.browse
will launch a browser and display a URL.
- Desktop.edit
will launch as appropriate editor of some sort on the given file.
- Desktop.mail
will launch the user’s favourite mail program.
- Desktop.print
will launch the appropriate application to print the given file.
Learning More
Oracle’s Javadoc on
exec package : available:
Oracle’s Javadoc on
Process class : available:
Oracle’s Javadoc on
ProcessBuilder class : available:
Oracle’s Javadoc on
Desktop class : available: