近日,实验室一同学想在Java程序中调用外部的jar命令来自动打包类文件,但是遇到了一个问题:jar命令的执行总是要等到该Java程序执行完成以后才立刻执行完。代码简要如下:
Process p = Runtime.getRuntime().exec("jar -cvf TestMy.jar *.class");
经过不断实验,发现JDK文档中描述如下:
The ProcessBuilder.start()
and Runtime.exec
methods create a native process and return an instance of a subclass of Process
that can be used to control the process and obtain information about it. The class Process
provides methods for performing input from the process, performing output to the process, waiting for the process to complete, checking the exit status of the process, and destroying (killing) the process.
The methods that create processes may not work well for special processes on certain native platforms, such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows, or shell scripts. The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (getOutputStream()
, getInputStream()
, getErrorStream()
). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock. (大致意思是当向子进程写入或从子进程读取流数据失败可能导致子进程阻塞甚至死锁)
The subprocess is not killed when there are no more references to the Process
object, but rather the subprocess continues executing asynchronously.
There is no requirement that a process represented by a Process
object execute asynchronously or concurrently with respect to the Java process that owns the Process
object.
正是红色标记的那句话道出了缘由:由于执行jar -cvf .......子进程向其输出流写入一些执行的信息因此可能导致阻塞甚至死锁,解决的办法十分简单只需用:jar -cf TestMy.jar *.class替代即可,去掉v以后表示执行jar命令而不向输出流写入信息。