1.Creation of Java Process
Java provides two methods to start a process or other program:
(1) Use Runtime's exec() method (2) Use ProcessBuilder's start() method (2)
1.1 ProcessBuilder
The ProcessBuilder class is a new class newly added in java.lang by J2SE 1.5. This class is used to create operating system processes. It provides a way to start and manage processes (that is, applications). Before J2SE 1.5, the process control and management were implemented by the Process class.
Each ProcessBuilder instance manages a set of process properties. The start() method uses these properties to create a new Process instance. The start() method can be called repeatedly from the same instance to create a new child process with the same or related properties.
Each process generator manages these process properties:
A command is a list of strings that represent the external program file to be called and its parameters (if any). Here, the list of strings representing valid operating system commands is system dependent. For example, every overall variable usually becomes an element in this list, but there are operating systems that want the program to mark the command line strings themselves - in such systems, Java implementations may require commands to include exactly these two element.
Environments are system-dependent mappings from variables to values. The initial value is a copy of the current process environment (see System.getenv()).
Working directory. The default value is the current working directory of the current process, usually named according to the system property user.dir.
redirectErrorStream property. Initially, this property is false, meaning that the standard output and error output of the child process are sent to two independent streams that can be accessed through the Process.getInputStream() and Process.getErrorStream() methods. If the value is set to true, the standard error is merged with the standard output. This makes it easier to associate error messages and corresponding output. In this case, the merged data can be read from the stream returned by Process.getInputStream(), while the stream read from Process.getErrorStream() will reach the end of the file directly.
Modifying the properties of the process builder will affect subsequent processes started by the object's start() method, but will never affect previously started processes or Java itself. Most error checks are performed by the start() method. The state of the object can be modified, but start() will fail in this way. For example, setting the command property to an empty list will not throw an exception unless start() is included.
Note that this class is not synchronous. If multiple threads access a ProcessBuilder at the same time, and at least one of the threads structurally modify one of the properties, it must keep external synchronization.
Summary of construction methods
ProcessBuilder(List<String> command)
Construct a process generator using specified operating system programs and parameters.
ProcessBuilder(String... command)
Construct a process generator using specified operating system programs and parameters.
Method Summary
List<String> command()
Returns the operating system programs and parameters of this process generator.
ProcessBuilder command(List<String> command)
Sets the operating system programs and parameters of this process generator.
ProcessBuilder command(String... command)
Sets the operating system programs and parameters of this process generator.
File directory()
Returns the working directory of this process generator.
ProcessBuilder directory(File directory)
Sets the working directory for this process generator.
Map<String,String> environment()
Returns a string mapping view of this process generator environment.
boolean redirectErrorStream()
Notify the process generator whether to merge standard errors and standard output.
ProcessBuilder redirectErrorStream(boolean redirectErrorStream)
Sets the redirectErrorStream property of this process generator.
Process start()
Start a new process using the properties of this process generator.
1.2 Runtime
Each Java application has a Runtime class instance, allowing the application to connect to the environment it runs. The current runtime can be obtained through the getRuntime method.
Applications cannot create their own Runtime class instances. However, you can use the getRuntime method to get the reference to the current Runtime runtime object. Once you get a reference to the current Runtime object, you can call the Runtime object method to control the state and behavior of the Java virtual machine.
Java code collection code
void addShutdownHook(Thread hook)
Register a new virtual machine to turn off the hook.
int availableProcessors()
Returns the number of available processors to the Java virtual machine.
Process exec(String command)
Execute the specified string command in a separate process.
Process exec(String[] cmdarray)
Execute specified commands and variables in a separate process.
Process exec(String[] cmdarray, String[] envp)
Execute specified commands and variables in a separate process of the specified environment.
Process exec(String[] cmdarray, String[] envp, File dir)
Execute specified commands and variables in separate processes in the specified environment and working directory.
Process exec(String command, String[] envp)
Execute the specified string command in a separate process of the specified environment.
Process exec(String command, String[] envp, File dir)
Execute the specified string command in a separate process with a specified environment and working directory.
void exit(int status)
Terminate the currently running Java virtual machine by starting the shutdown sequence of the virtual machine.
long freeMemory()
Returns the amount of free memory in the Java virtual machine.
void gc()
Run the garbage collector.
InputStream getLocalizedInputStream(InputStream in)
Obsolete. Starting with JDK 1.1, the preferred method for converting a locally encoded byte stream to a Unicode character stream is to use the InputStreamReader and BufferedReader classes.
OutputStream getLocalizedOutputStream(OutputStream out)
Obsolete. Starting with JDK 1.1, the preferred method for converting a Unicode character stream to a locally encoded byte stream is to use the OutputStreamWriter, BufferedWriter, and PrintWriter classes.
static Runtime getRuntime()
Returns the runtime object associated with the current Java application.
void halt(int status)
Forced terminate the currently running Java virtual machine.
void load(String filename)
Loads the specified file name as the dynamic library.
void loadLibrary(String libname)
Loads a dynamic library with the specified library name.
long maxMemory()
Returns the maximum amount of memory the Java virtual machine tries to use.
boolean removeShutdownHook(Thread hook)
Unregister a previously registered virtual machine to turn off the hook.
void runFinalization()
Runs the terminating method of all objects that suspend finalization.
static void runFinalizersOnExit(boolean value)
Obsolete. This method itself is unsafe. It may call a final method on the object being used, while other threads are operating on those objects, resulting in incorrect behavior or deadlocks.
long totalMemory()
Returns the total amount of memory in the Java virtual machine.
void traceInstructions(boolean on)
Enable/disable command tracking.
void traceMethodCalls(boolean on)
Enable/disable method call tracking.
1.3 Process
No matter which method is used to start the process, an instance of the Process class represents the started process will be returned, which can be used to control the process and obtain relevant information. The Process class provides methods to execute from process input, execution output to process, wait for process completion, check the process's exit status, and destroy (kill) the process:
void destroy()
Kill the child process.
Generally speaking, this method cannot kill the process that has been started, so it is better not to use it.
int exitValue()
Returns the exit value of the child process.
The exitValue() method will have a normal return value only after the startup process has completed its execution or exited due to an exception, otherwise an exception will be thrown.
InputStream getErrorStream()
Gets the error stream of the child process.
If the error output is redirected, the error output cannot be read from the stream.
InputStream getInputStream()
Gets the input stream of the child process.
The standard output of the process can be read from this stream.
OutputStream getOutputStream()
Gets the output stream of the child process.
The data written to the stream is used as standard input to the process.
int waitFor()
Causes the current thread to wait, if necessary, until the process represented by the Process object has terminated.
2. Multi-process programming examples
Generally, when we run methods in other classes in Java, whether they are static or dynamic calls, they are executed in the current process, that is, there is only one java virtual machine instance running. Sometimes, we need to start multiple java subprocesses through java code. Although doing this takes up some system resources, it will make the program more stable because the newly started program runs in different virtual machine processes. If an exception occurs in one process, it will not affect other child processes.
In Java we can use two methods to achieve this requirement. The easiest way is to execute java classname through the exec method in Runtime. If the execution is successful, this method returns a Process object. If the execution fails, an IOException error will be thrown. Let's take a look at a simple example below.
// Test1.java file import java.io.*;public class Test{ public static void main(String[] args) { FileOutputStream fOut = new FileOutputStream("c://Test1 .txt"); fOut.close() ; System.out.println("Called successfully!"); }}// Test_Exec.javapublic class Test_Exec{ public static void main(String[] args) { Runtime run = Runtime.ge tRuntime(); Process p = run. exec("java test1"); }}After running the program through java Test_Exec, I found that there was an additional Test1.txt file on the C drive, but the output information "Called successfully!" did not appear in the console. Therefore, it can be concluded that Test has been executed successfully, but for some reason, the output information of Test is not output in the console of Test_Exec. This reason is also very simple, because the child process of Test_Exec is created using exec. This child process does not have its own console, so it does not output any information.
If you want to output the output information of the child process, you can obtain the output stream of the child process through getInputStream in Process (output in the child process, input in the parent process), and then transfer the output stream of the child process from the parent process's console Output. The specific implementation code is as follows:
// Test_Exec_Out.javaimport java.io.*;public class Test_Exec_Out{ public static void main(String[] args) { Runtime run = Runtime.getRuntime (); Process p = run.exec("java test1"); BufferedInputStream in = new BufferedInputStream(p.getInputStream()); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String s; while ((s = br.readLine()) != null) System.out.println(s) ; }}As can be seen from the above code, in Test_Exec_Out.java, the output information of the child process is read by row, and then the output is performed on each line in Test_Exec_Out. The above discussion is how to get the output information of the child process. Then, in addition to output information, there is also input information. Since the child process does not have its own console, the input information must also be provided by the parent process. We can provide input information to the child process through the getOutputStream method of Process (that is, input information from the parent process to the child process, rather than input information from the console). We can look at the following code:
// Test2.java file import java.io.*;public class Test{ public static void main(String[] args) { BufferedReader br = new BufferedReader(new InputStreamRead er(System.in)); System.out.println(" Information entered by the parent process: " + br.readLine()); }}// Test_Exec_In.javaimport java.io.*;public class Test_Exec_In{ public static void main(String[] args) { Run time run = Runtime.getRuntime (); Process p = run.exec("java test2"); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream())); bw.write("Output to child process information"); bw.flush( ); bw.close(); // The stream must be closed, otherwise information cannot be entered into the child process// System.in.read(); }} From the above code, we can see that Test1 gets the information sent by Test_Exec_In and outputs it. When you do not add bw.flash() and bw.close(), the information will not reach the child process, which means that the child process enters a blocking state, but since the parent process has exited, the child process also exits. If you want to prove this, you can add System.in.read() at the end and then view the java process through the task manager (under windows), and you will find that if you add bw.flush() and bw.close() , only one java process exists, if they are removed, two java processes exist. This is because if the information is passed to Test2, Test2 exits after obtaining the information. Here is one thing to be explained that the execution of exec is asynchronous and will not stop executing the following code because a certain program that is executed is blocked. Therefore, after running test2, the following code can still be executed.
The exec method has been reloaded many times. What is used above is just an overload of it. It can also separate commands and parameters, such as exec("java.test2") can be written as exec("java", "test2"). Exec can also run Java virtual machines with different configurations through specified environment variables.
In addition to using Runtime's exec method to build a child process, you can also build a child process through ProcessBuilder. The use of ProcessBuilder is as follows:
// Test_Exec_Out.javaimport java.io.*;public class Test_Exec_Out{ public static void main(String[] args) { ProcessBuilder pb = new ProcessBui lder("java", "test1"); Process p = pb.start(); … … }}In establishing child processes, ProcessBuilder is similar to Runtime. Different ProcessBuilders use the start() method to start the child process, while Runtime uses the exec method to start the child process. After getting the Process, their operations are exactly the same.
Like Runtime, ProcessBuilder can also set the environment information, working directory, etc. of the executable file. The following example describes how to set this information using ProcessBuilder.
ProcessBuilder pb = new ProcessBuilder("Command", "arg2", "arg2", ''');// Set environment variable Map<String, String> env = pb.environment();env.put("key1", : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : "value1");env.remove("key2");env.put("key2", env.get("key1") + "_test"); pb.directory("../abcd"); // Set the working directory Process p = pb.start(); // Create a child process