2012-09-27 98 views
3

我正在启动一个服务(进程),下面的代码。我的问题是:从阻止进程中优雅退出

  • 我需要读取过程的输出,以确保它得到启动
  • ,如果它得到开始,我回来,一切都很好
  • ,如果它不上手无论出于何种原因,在同时将永远阻止的过程只是挂起,而不输出任何东西

任何想法我如何能正常退出的方法,如果我没有得到期望的字符串?

PS:我可以用一个未来超时做它,但还是觉得有可能是一个更好的办法。

public boolean startService() { 
    try { 
     ProcessBuilder pb = new ProcessBuilder("service.exe"); 
     pb.directory(new File("C:/serviceFolder/")); 
     pb.redirectErrorStream(true); 
     Process p = pb.start(); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 
     String line; 
     while ((line = reader.readLine()) != null) { 
      if (line.toLowerCase().contains("started")) { 
       return true; 
      } 
     } 
     return false; //I never get there when it fails 
    } catch (IOException e) { 
     throw new RuntimeException("Could not start the service.exe process", e); 
    }   
} 
+3

一个'Future'一个超时*为*更好的办法 – Bohemian

回答

2

如果你可以修改服务代码,最好改变,如果它不能启动它不挂 - 它应该退出并记录错误消息。这样你的Java代码将按原样工作。

如果你不能,除了设置超时之外没有别的办法,因为你的Java代码无法知道发生了什么。

当然,如果您可以修改服务,另一种方法是监视输出,而不是过程的标准输出/错误,如PID文件,错误日志消息或其他。如果子进程已经创建了一个PID文件,例如,您可以安排在该文件,而不是标准输入支票,但实际上它是同一个概念,只是适用不同使用更好/更简单的代码

0

像这样的东西应该工作。实质上,在一个单独的线程中启动该服务,并创建一个Timer,在一段时间后它会中断它。请注意,计时器任务是Daemon,因此如果需要退出,它不应阻塞您的进程。

如果reader.readLine()消耗并丢弃中断,显然这不起作用。

private static class ServiceRunner implements Runnable { 
    // Am I running? 
    volatile boolean running = true; 
    // My thread. 
    volatile Thread thread = Thread.currentThread(); 

    @Override 
    public void run() { 
    // Start a timer. 
    Timer timer = new Timer("Wait for ServiceRunner to finish.", true); 
    // Fire it after 2 seconds. 
    timer.schedule(new StopTask(), 2000); 
    try { 
     // Start the service. 
     startService(); 
    } finally { 
     // No longer running. 
     running = false; 
    } 
    } 

    class StopTask extends TimerTask { 

    @Override 
    public void run() { 
     if (running) { 
     // Interrupt the service runner. 
     thread.interrupt(); 
     } 
    } 
    } 

    public boolean startService() { 
    try { 
     ProcessBuilder pb = new ProcessBuilder("service.exe"); 
     pb.directory(new File("C:/serviceFolder/")); 
     pb.redirectErrorStream(true); 
     Process p = pb.start(); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 
     String line; 
     while ((line = reader.readLine()) != null) { 
     if (line.toLowerCase().contains("started")) { 
      return true; 
     } 
     } 
     return false; //I never get there when it fails 
    } catch (IOException e) { 
     throw new RuntimeException("Could not start the service.exe process", e); 
    } 
    } 
} 

我还没有测试过这段代码,但它应该可以工作。

您将需要做出调整,以保持服务是否启动与否。

+0

谢谢,但看起来像未来#重新实现与超时得到。 – assylias

+0

如果超时过期,Future.get会中止操作吗?这样做。然而,我同意这可以很容易地通过“FutureTask”实现。 – OldCurmudgeon

+0

超时时,它会尝试中断正在运行的任务,在我的情况下会抛出InterruptedException。 – assylias

0

看来,Future#get是更可取的。对于未来的参考,我已经修改了代码如下方式:

public boolean startService() { 

    Callable<Boolean> start = new Callable<Boolean>() { 
     @Override 
     public Boolean call() throws Exception { 
      ProcessBuilder pb = new ProcessBuilder("service.exe"); 
      pb.directory(new File("C:/serviceFolder/")); 
      pb.redirectErrorStream(true); 
      Process p = pb.start(); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 
      String line; 
      while ((line = reader.readLine()) != null) { 
       if (line.toLowerCase().contains("started")) { 
        return true; 
       } 
      } 
      return false; 
     } 
    }; 

    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    Future<Boolean> future = executor.submit(start); 

    try { 
     return future.get(1, TimeUnit.SECONDS); 
    } catch (InterruptedException ignore) { 
     Thread.currentThread().interrupt(); 
     return false; 
    } catch (ExecutionException | TimeoutException e) { 
     logger.error("Could not start service", e); 
     return false; 
    } finally { 
     executor.shutdownNow(); 
    } 
}