【问题标题】:Implement `Process.waitFor(long timeout, TimeUnit unit)` in Java 6在 Java 6 中实现 `Process.waitFor(long timeout, TimeUnit unit)`
【发布时间】:2019-05-04 14:38:11
【问题描述】:

我正在处理一个遗留 (Java 6/7) 项目,该项目使用 ProcessBuilder 以与操作系统无关的方式从机器请求 UUID。我想使用Java 8 中的Process.waitFor(long timeout, TimeUnit unit) 方法,但这在Java 6 中没有实现。相反,我可以使用waitFor(),它会阻塞直到完成或出错。

如果可能,我希望避免将使用的 Java 版本升级到 8,因为这需要进行许多其他更改(例如,将代码从已删除的内部 API 中迁移出来并升级生产 Tomcat 服务器)。

我怎样才能最好地实现执行进程的代码,并超时?我正在考虑以某种方式实施一个计划来检查进程是否仍在运行,如果是,则取消/销毁它并且已达到超时。

我当前的 (Java 8) 代码如下所示:

/** USE WMIC on Windows */
private static String getSystemProductUUID() {
    String uuid = null;
    String line;

    List<String> cmd = new ArrayList<String>() {{
      add("WMIC.exe"); add("csproduct"); add("get"); add("UUID");
    }};

    BufferedReader br = null;
    Process p = null;
    SimpleLogger.debug("Attempting to retrieve Windows System UUID through WMIC ...");
    try {
      ProcessBuilder pb = new ProcessBuilder().directory(getExecDir());
      p = pb.command(cmd).start();

      if (!p.waitFor(TIMEOUT, SECONDS)) { // No timeout in Java 6
        throw new IOException("Timeout reached while waiting for UUID from WMIC!");
      }
      br = new BufferedReader(new InputStreamReader(p.getInputStream()));
      while ((line = br.readLine()) != null) {
        if (null != line) {
          line = line.replace("\t", "").replace(" ", "");
          if (!line.isEmpty() && !line.equalsIgnoreCase("UUID")) {
            uuid = line.replace("-", "");
          }
        }
      }
    } catch (IOException | InterruptedException ex) {
      uuid = null;
      SimpleLogger.error(
        "Failed to retrieve machine UUID from WMIC!" + SimpleLogger.getPrependedStackTrace(ex)
      );
      // ex.printStackTrace(System.err);
    } finally {
      if (null != br) {
        try {
          br.close();
        } catch (IOException ex) {
          SimpleLogger.warn(
            "Failed to close buffered reader while retrieving machine UUID!"
          );
        }
        if (null != p) {
          p.destroy();
        }
      }
    }

    return uuid;
  }

【问题讨论】:

标签: processbuilder java-6


【解决方案1】:

您可以使用以下仅使用 Java 6 下可用功能的代码:

public static boolean waitFor(Process p, long t, TimeUnit u) {
    ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
    final AtomicReference<Thread> me = new AtomicReference<Thread>(Thread.currentThread());
    ScheduledFuture<?> f = ses.schedule(new Runnable() {
        @Override public void run() {
            Thread t = me.getAndSet(null);
            if(t != null) {
                t.interrupt();
                me.set(t);
            }
        }
    }, t, u);
    try {
        p.waitFor();
        return true;
    }
    catch(InterruptedException ex) {
        return false;
    }
    finally {
        f.cancel(true);
        ses.shutdown();
        // ensure that the caller doesn't get a spurious interrupt in case of bad timing
        while(!me.compareAndSet(Thread.currentThread(), null)) Thread.yield();
        Thread.interrupted();
    }
}

请注意,与您可以在某处找到的其他解决方案不同,这将在调用者的线程中执行Process.waitFor() 调用,这是您在使用监控工具查看应用程序时所期望的。它还有助于短期运行子进程的性能,因为调用者线程不会比Process.waitFor() 做更多的事情,即不需要等待后台线程的完成。取而代之的是,如果超时时间已过,则后台线程会中断启动线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 2021-09-03
    • 2023-03-06
    • 1970-01-01
    相关资源
    最近更新 更多