浅析Java执行外部命令的几个要点(2)——如何支持Timeout

本文介绍如何在Java中处理外部命令执行的超时问题。通过自定义`CommandExec`类,利用`Runtime.exec()`方法并设置超时限制,当超过设定时间,程序会强制终止并记录错误日志。代码示例展示了如何创建和使用这个类来执行带有超时控制的外部命令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转贴请注明出处:http://blog.youkuaiyun.com/froole

用Java执行外部命令非常简单,只要在带入参数的时候注意不要把参数弄错就可以了。
但是,在实际运用中,还有一个比较棘手的问题,就是外部命令执行的timeout。
特别是执行时间比较长的外部命令,如外部的后台处理程序。
当执行这些程序的时候不可能任由他们随便跑,大多数时候,都要事先设定一个外部命令的最大执行时限,也就是timeout,如果超过这个时间程序还没有执行完成,那么将强制杀死程序,并输出错误日志。
JDK的外部执行API没有提供设定timeout的接口,所以,实现此功能,只能自行解决。

在判断执行结果的时候,将会一直对Process的返回值进行判断,前面的部分已经介绍了Process的使用特点,这里将不再重复,只放出代码,如下:

  1. import java.io.File;
  2. import java.io.IOException;
  3. /**
  4.  * 支持timeout的执行外部命令的类定义。<br>
  5.  *
  6.  * @version 1.0
  7.  * @author hao_shunri
  8.  * @see http://blog.youkuaiyun.com/froole
  9.  */
  10. public class CommandExec {
  11.     /**
  12.      * 用来执行外部命令的{@link Runtime}实现
  13.      */
  14.     private Runtime runtime;
  15.     /**
  16.      * 默认确认timeout的间隔时间,単位:毫秒
  17.      */
  18.     private static final int DEFAULT_TIMEOUT_INTERVAL = 500;
  19.     /**
  20.      * 默认timeout
  21.      */
  22.     private static final long DEFAULT_TIMEOUT = 60 * 1000;
  23.     /**
  24.      * Timout时间,単位:毫秒
  25.      */
  26.     private long timeout = -1;
  27.     /**
  28.      * 确认timeout的间隔时间,単位:毫秒
  29.      */
  30.     private long interval;
  31.     /**
  32.      *
  33.      * @param runtime 用来执行外部命令的{@link Runtime}实现
  34.      * @param timeout timeout时间
  35.      * @param invterval 换算timeout的间隔时间
  36.      */
  37.     public CommandExec(Runtime runtime, long timeout, long invterval){
  38.         this.timeout = timeout;
  39.         this.interval = invterval;
  40.         this.runtime = runtime;
  41.     }
  42.     /**
  43.      *
  44.      *
  45.      * @param timeout timeout时间
  46.      * @param invterval 换算timeout的间隔时间
  47.      */
  48.     public CommandExec(long timeout, long invterval){
  49.         this(Runtime.getRuntime(), timeout, invterval);
  50.     }
  51.     /**
  52.      *
  53.      *
  54.      * @param timeout timeout时间
  55.      */
  56.     public CommandExec(long timeout){
  57.         this(timeout, DEFAULT_TIMEOUT_INTERVAL);
  58.     }
  59.     /**
  60.      *
  61.      *
  62.      */
  63.     public CommandExec(){
  64.         this(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_INTERVAL);
  65.     }
  66.     /**
  67.      *
  68.      * 执行外部命令
  69.      *
  70.      * @param commands
  71.      *            命令数组
  72.      * @return
  73.      * @throws IOException
  74.      */
  75.     public Process exec(String[] commands) throws IOException, InterruptedException {
  76.         return exec(commands, null);
  77.     }
  78.     /**
  79.      * 执行外部命令
  80.      *
  81.      * @param commands
  82.      *            命令数组
  83.      * @param dir
  84.      *            临时目录
  85.      * @return
  86.      * @throws IOException
  87.      */
  88.     public Process exec(String[] commands, File dir) throws IOException, InterruptedException {
  89.         return exec(commands, null, dir);
  90.     }
  91.     /**
  92.      *
  93.      * 执行外部命令
  94.      *
  95.      * @param commands
  96.      *            命令数组
  97.      * @param envp
  98.      *            环境变量
  99.      * @param dir
  100.      *            临时目录
  101.      * @return
  102.      * @throws IOException
  103.      * @throws IllegalThreadStateException
  104.      */
  105.     public Process exec(String[] commands, String[] envp, File dir) throws IOException, InterruptedException {
  106.         if (commands == null) {
  107.             throw new NullPointerException();
  108.         }
  109.         Process process = runtime.exec(commands, envp, dir);
  110.         // 设定timeout
  111.         long limitTime = timeout + System.currentTimeMillis();
  112.         // 状态
  113.         Integer status = null;
  114.         do {
  115.             try {
  116.                 status = process.exitValue();
  117.                 break;
  118.             } catch (IllegalThreadStateException e) {
  119.                 try {
  120.                     Thread.sleep(getInterval());
  121.                 } catch (InterruptedException we) {
  122.                     return null;
  123.                 }
  124.             }
  125.         } while (System.currentTimeMillis() < limitTime);
  126.         if (status == null) {
  127.             process.destroy();
  128.             try {
  129.                 status = process.waitFor();
  130.             } catch (InterruptedException e) {
  131.                 throw e;
  132.             }
  133.         }
  134.         return process;
  135.     }
  136.     /**
  137.      * 设定Timout时间,単位:毫秒
  138.      *
  139.      * @param timeout
  140.      *            Timout时间,単位:毫秒
  141.      */
  142.     public void setTimeout(long timeout) {
  143.         this.timeout = timeout;
  144.     }
  145.     /**
  146.      * 提取Timout时间,単位:毫秒
  147.      *
  148.      * @return Timout时间,単位:毫秒
  149.      */
  150.     public long getTimeout() {
  151.         return timeout;
  152.     }
  153.     /**
  154.      * 提取确认timeout的间隔时间,単位:毫秒
  155.      *
  156.      * @return 确认timeout的间隔时间,単位:毫秒
  157.      */
  158.     public long getInterval() {
  159.         return interval;
  160.     }
  161.     /**
  162.      * 设定确认timeout的间隔时间,単位:毫秒
  163.      *
  164.      * @param interval
  165.      *            确认timeout的间隔时间,単位:毫秒
  166.      */
  167.     public void setInterval(long interval) {
  168.         this.interval = interval;
  169.     }
  170. }

待续

相关:
-浅析Java执行外部命令的几个要点(1)
-浅析Java执行外部命令的几个要点(2)
-浅析Java执行外部命令的几个要点(3)
-浅析Java执行外部命令的几个要点(4)

<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>
转贴请注明出处:http://blog.youkuaiyun.com/froole

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值