使用Apache Commons Exec管理进程

来源:互联网 发布:客户管理系统源码下载 编辑:程序博客网 时间:2024/06/06 09:21

网上竟然搜不到详细一点的帖子,估计大家用JAVA去管理进程的场景比较少吧,只好自己总结一个。

Java管理进程,API级别是使用:Runtime.getRuntime().exec(“shell”);这个方法。
Java在执行命令时输出到某个Buffer里,这个Buffer是有容量限制的,如果满了一直没读取,就会一直等待,造成进程锁死的现象。
使用Apache Commons Exec,应该可以避免很多类似的坑。
它提供一些常用的方法用来执行外部进程,另外,它提供了监视狗Watchdog来设监视进程的执行超时,同时也还实现了同步和异步功能,
Apache Commons Exec涉及到多线程,比如新启动一个进程,Java中需要再开三个线程来处理进程的三个数据流,分别是标准输入,标准输出和错误输出。

1.基本用法

就三步:
1)创建命令行:CommandLine
2)创建执行器:DefaultExecutor
3)用执行器执行命令:executor.execute(cmdLine);

String cmdStr = "ping www.baidu.com -t";final CommandLine cmdLine = CommandLine.parse(cmdStr);DefaultExecutor executor = new DefaultExecutor();int exitValue = executor.execute(cmdLine);

关于这个exitValue
一般的进程,其运行结束后,默认值为0。
对于某些有特殊退出值的程序,需要确定知道其值是什么,然后用executor.setExitValue(退出值);进行明确设置,否则,会出现ExecuteException。
比如,写一个JAVA程序,在main函数中,用System.exit(10);退出程序,用Exec管理这个进程就必须设置:executor.setExitValue(10);
如果程序有多个退出值,可使用executor.setExitValues(int[]);函数进行处理。

1.1 通过添加参数方式构建命令。这是官方推荐的方式!
上面的程序可以改为:

final CommandLine cmdLine = new CommandLine("ping");cmdLine.addArgument("www.baidu.com");cmdLine.addArgument("-t");DefaultExecutor executor = new DefaultExecutor();int exitValue = executor.execute(cmdLine);

2.超时管理–进程执行时间的管理

设置外部命令执行等待时间,如果超过设置的等待时间,则中断执行。

final CommandLine cmdLine = CommandLine.parse("ping www.baidu.com -t");ExecuteWatchdog watchdog = new ExecuteWatchdog(5000);//设置超时时间:5秒DefaultExecutor executor = new DefaultExecutor();executor.setWatchdog(watchdog);executor.setExitValue(1);//由于ping被到时间终止,所以其默认退出值已经不是0,而是1,所以要设置它int exitValue = executor.execute(cmdLine);

3.非阻塞方式执行进程

上面的执行外部命令都是阻塞式,也就是在执行外部命令时,当前线程是阻塞的。
比如执行ping -t,当成的JAVA程序会一直等着不会停止。
解决办法:使用DefaultExecuteResultHandler处理外部命令执行的结果,释放当前线程。

final CommandLine cmdLine = CommandLine.parse("ping www.baidu.com -t");final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();DefaultExecutor executor = new DefaultExecutor();executor.execute(cmdLine, resultHandler);//这里开始的代码会被立即执行下去,因为上面的语句不会被阻塞。resultHandler.waitFor(5000);//等待5秒。

可以使用waitFor来阻塞处理逻辑,比如上面的代码,在执行到waitFor时,会等待5秒再继续执行。
之后,可以通过resultHandler.hasResult()、resultHandler.getExitValue()、resultHandler.getException()获得需要信息。
注意:getException();得到的是Exec自己的异常,不是应用程序(比如JAVA)代码里面抛出的异常。

4.终止进程

通过Watchdog,可以终止正在运行的进程。

final CommandLine cmdLine = 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(cmdLine, 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,看看进程状态是什么。

5.获得进程的输出信息

可以在程序中,通过PumpStreamHandler,截获进程的各种输出,包括output 和 error stream。

String cmdStr = "ping www.baidu.com";final CommandLine cmdLine = CommandLine.parse(cmdStr);DefaultExecutor executor = new DefaultExecutor();ByteArrayOutputStream baos = new ByteArrayOutputStream();executor.setStreamHandler(new PumpStreamHandler(baos, baos));executor.setExitValue(1);int exitValue = executor.execute(cmdLine);final String result = baos.toString().trim();System.out.println(result);//这个result就是ping输出的结果。如果是JAVA程序,抛出了异常,也被它获取。
0 0
原创粉丝点击