Java的Runtime、Process类介绍及Runtime.getRuntime().exec方法的使用及问题

1. Runtime的定义

Runtime类是单实例的,每个Java应用程序都有一个该类的实例,它允许应用程序和运行应用程序的环境进行交互。可使用getRuntime方法获取该类的实例。

2. 常用方法
方法 作用
getRuntime():Runtime 返回与当前Java应用程序关联的运行时对象。
exec(String):Process 在单独的进程中执行指定的字符串命令的方法。该方法会返回一个Process的实例,该方法有许多的重载,参见jdk源码
freeMemory():long 返回Java虚拟机中的可用内存量
totalMemory():long 返回Java虚拟机中的内存总量
maxMemory():long 返回Java虚拟机将尝试使用的最大内存量。
exit(int):void 通过启动其关闭序列来终止当前运行的Java虚拟机。此方法永远不会正常返回。参数用作状态代码;按照惯例,非零状态代码表示*异常终止。System.exit(int)其实就是调用该方法执行的
3. Runtime.getRuntime().exec()方法详解

使用exec方法执行字符串命令并返回一个process对象,下图是一个简单的示例:
Java的Runtime、Process类介绍及Runtime.getRuntime().exec方法的使用及问题
exitValue方法使用于返回子进程的退出值,但是方法不会阻塞,也就是说在调用该方法时如果子进程尚未终止则会抛出IllegalThreadStateException异常。
如果需要等待子进程执行完毕,在继续运行程序,可以使用process.waitFor()方法,该方法是一个阻塞方法,直到process的自己进程运行结束才会返回,0表示正常终止。
destroy()方法用于杀死子进程。
isAlive()返回子进程的存活状态。

4. process.waitFor()可能造成死锁问题

这里先解释一下Process类的3个流获取方法:

方法 说明
getOutputStream() :OutputStream 获取子进程输入的输出流
getInputStream() :InputStream 这里是获取子进程输出的输入流
getErrorStream() :InputStream 获取自己进程错误输出的输入流

这里可能解释的不够清楚,首先子进程是指我们使用exec方法执行的进程,以getInputStream()方法为例,子进程的输出对于我们程序的进程是输入,所有相对java程序而言是输入流。

继续,waitFor()这个方法往往会因为子进程的阻塞而导致我们的程序发生死锁。
因为本地的系统对标准输入和输出所提供的缓冲池有限,所以错误的对标准输出快速的写入和从标准输入快速的读入都有可能造成子进程死锁。问题的关键在缓冲区这个地方:可执行程序的标准输出比较多,而运行窗口的标准缓冲区不够大,所以发生阻塞。接着来分析缓冲区,当Runtime对象调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立三个管道连接:标准输入,标准输出和标准错误流。假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitFor()这里。

简单的修改程序:
Java的Runtime、Process类介绍及Runtime.getRuntime().exec方法的使用及问题

参考:
JDK源码
https://www.cnblogs.com/mingforyou/p/3551199.html
https://www.cnblogs.com/xriverside/p/4362609.html