我正在处理一个旧版(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;
}
答案 0 :(得分:2)
您可以使用以下代码,该代码仅使用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()
多得多,即不需要等待后台线程的完成。而是在后台thead中发生的事情是,如果超时,则启动线程将中断。