Java管理进程,API级别是使用:Runtime.getRuntime().exec(“shell”);这个方法。
Java在执行命令时输出到某个Buffer里,这个Buffer是有容量限制的,如果满了一直没读取,就会一直等待,造成进程锁死的现象。想要避免这种阻塞有一种简单的方法,重定向标准输入流以及标准错误流来接收执行命令后的输出。另一种方法就是使用Apache Commons Exec,可以避免很多类似的坑。 它提供一些常用的方法用来执行外部进程,另外,它提供了监视狗Watchdog来设监视进程的执行超时,同时也还实现了同步和异步功能, Apache Commons Exec涉及到多线程,比如新启动一个进程,Java中需要再开三个线程来处理进程的三个数据流,分别是标准输入,标准输出和错误输出。
基本用法
1、创建命令行:CommandLine
2、创建执行器:DefaultExecutor
3、用执行器执行命令:executor.execute(cmdLine);
execute(String command)方法的返回值,int类型的返回值,一般的进程,其运行结束后,默认值为0。
对于某些有特殊退出值的程序,需要确定知道其值是什么,然后用executor.setExitValue(退出值);进行明确设置,否则,会出现ExecuteException。 比如,写一个JAVA程序,在main函数中,用System.exit(10);退出程序,用Exec管理这个进程就必须设置:executor.setExitValue(10); 如果程序有多个退出值,可使用executor.setExitValues(int[]);函数进行处理。
2、创建执行器:DefaultExecutor
3、用执行器执行命令:executor.execute(cmdLine);
String command= "ping www.baidu.com -t";
final CommandLine commandLine = CommandLine.parse(command);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(commandLine );
关于这个exitValue: execute(String command)方法的返回值,int类型的返回值,一般的进程,其运行结束后,默认值为0。
对于某些有特殊退出值的程序,需要确定知道其值是什么,然后用executor.setExitValue(退出值);进行明确设置,否则,会出现ExecuteException。 比如,写一个JAVA程序,在main函数中,用System.exit(10);退出程序,用Exec管理这个进程就必须设置:executor.setExitValue(10); 如果程序有多个退出值,可使用executor.setExitValues(int[]);函数进行处理。
1、构建命令,官方推荐通过添加参数的方法构建命令,上面的代码可以修改如下:
final CommmandLine commandLine = new CommandLine("ping");
conmmandLine.addArgument("www.baidu.com");
conmmandLine.addArgument("-t");
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(commandLine);
超时管理-管理进程执行的时间
设置外部命令执行等待的时间,如果外部命令在指定时间内没有完成,则中断执行。
final CommandLine commandLine = CommandLine.parse("ping www.baidu.com -t");
ExecuteWatchdog watchdog = new ExecuteWatchdog(5000);//设置超时时间:5秒
DefaultExecutor executor = new DefaultExecutor();
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);
非阻塞方式执行进程
上面的执行外部命令都是阻塞式,也就是在执行外部命令时,当前线程是阻塞的。
比如执行ping -t,当前的JAVA程序
比如执行ping -t,当前的JAVA程序
会一直等着不会停止。
解决办法:使用DefaultExecuteResultHandler处理外部命令执行的结果,释放当前线程。
解决办法:使用DefaultExecuteResultHandler处理外部命令执行的结果,释放当前线程。
final CommandLine commandLine = CommandLine.parse("ping www.baidu.com -t");
final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
DefaultExecutor executor = new DefaultExecutor();
executor.execute(commandLine , resultHandler);
//这里开始的代码会被立即执行下去,因为上面的语句不会被阻塞。
resultHandler.waitFor(5000);//等待5秒。
可以使用waitFor来阻塞处理逻辑,比如上面的代码,在执行到waitFor时,会等待5秒再继续执行。 之后,可以通过resultHandler.hasResult()、resultHandler.getExitValue()、resultHandler.getException()获得需要信息。 注意:getException();得到的是Exec自己的异常,不是应用程序(比如JAVA)代码里面抛出的异常。终止进程
通过Watchdog,可以终止正在运行的进程。
final CommandLine commandLine = CommandLine.parse("ping www.baidu.com -t");
final ExecuteWatchdog watchdog = new ExecuteWatchdog(Integer.MAX_VALUE);
final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
DefaultExecutor executor = new DefaultExecutor();
executor.setWatchdog(watchdog);
executor.execute(commandLine , resultHandler);
Thread.sleep(10000);//等进程执行一会,再终止它
System.out.println("--> Watchdog is watching ? " + watchdog.isWatching());
watchdog.destroyProcess();//终止进程
System.out.println("--> destroyProcess done.");
System.out.println("--> Watchdog is watching ? " + watchdog.isWatching());
System.out.println("--> Watchdog should have killed the process : " + watchdog.killedProcess());
System.out.println("--> wait result is : " + resultHandler.hasResult());
System.out.println("--> exit value is : " + resultHandler.getExitValue());
System.out.println("--> exception is : " + resultHandler.getException());
resultHandler.waitFor(5000);//等待5秒。下面加上上面的几个System.out,看看进程状态是什么。
获得进程的输出信息
可以在程序中,通过PumpStreamHandler,截获进程的各种输出,包括output
和 error stream。
String command = "ping www.baidu.com";
final CommandLine commandLine = CommandLine.parse(command );
DefaultExecutor executor = new DefaultExecutor();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
executor.setStreamHandler(new PumpStreamHandler(baos, baos));
executor.setExitValue(1);
int exitValue = executor.execute(commandLine );
final String result = baos.toString().trim();
System.out.println(result);//这个result就是ping输出的结果。如果是JAVA程序,抛出了异常,也被它获取。
Apache Commons Exec为Java提供了方便的外部进程管理工具,包括基本用法、超时管理、非阻塞执行和进程控制。通过使用该库,可以避免标准输入/输出流引起的阻塞问题,实现进程执行的超时监控,并能异步处理进程的输出信息,确保进程的稳定运行。
1388

被折叠的 条评论
为什么被折叠?



