概述
在编写Java程序时,有时候我们需要调用外部的exe,这时可以通过Runtime的exec()方法,
该命令使用比较简单,但是无法对执行做细节的控制。
通过使用ProcessBuilder构建Process可以进行细节的控制,但是默认process是阻塞的。
public abstract int waitFor() throws InterruptedException;
public boolean waitFor(long timeout, TimeUnit unit)
不要被boolean waitFor(long timeout, TimeUnit unit)
误解,他也是阻塞的,阻塞到process进程执行完,才进行是否超时的判断。
并不是说当超时时他会自动结束。
通过process.destroy()
方法可以从外部终止该process。
但是waitFor时主进程阻塞是阻塞的。我们需要在外部开启一条线程,把waitFor这个阻塞操作放到这条线程,同时主线程进行计时,
如果到了限定时间还未执行完毕,那么就调用process.destroy()
kill掉该进程。
具体代码思路
首先是一个ProcessWorker类,也就是之前说的用来放置waitFor,阻塞的线程,它继承Thread,实现了run方法。
它记录以下几个状态,通过volatile来确保外部线程可见:
private volatile int exitCode = -99;
private volatile boolean completed = false;
private volatile String output = "";
在run方法中,通过try with resource来读取该进程的输出,
并且设置waitFor,当等待结束时,设置completed为true。
try (InputStreamReader reader = new InputStreamReader(
process.getInputStream(), DEFAULT_ENCODING)) {
StringBuilder log = new StringBuilder();
char[] buffer = new char[BUFFER_SIZE];
int length;
while ((length = reader.read(buffer)) != -1) {
log.append(buffer, 0, length);
}
output = log.toString();
exitCode = process.waitFor();
completed = true;
} catch (InterruptedException | IOException e) {
Thread.currentThread().interrupt();
}
ProcessWorker 完整代码
private static class ProcessWorker extends Thread {
private final Process process;