Я использую ProcessBuilder
в Java для запуска процесса.Я хочу, чтобы моя программа ждала Process
, пока в ее выходном потоке не будет строки, соответствующей заданному шаблону, или пока не превысит ограничение по времени.
Я использую BufferedReader
, чтобы читать строку за строкой из Process.getOutputStream
при сопоставлении каждой строки с шаблоном.Он работал нормально, когда есть совпадение или процесс прервался перед любым совпадением.Но когда процесс больше не выводит строку после заданного временного ограничения, блок BufferedReader.readLine()
и чтение потока из Process.getOutputStream
никогда не завершаются.
Вот мой код.
private static Timer setTimeout(Runnable runnable, long timeoutMillis) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
runnable.run();
timer.cancel();
}
}, timeoutMillis);
return timer;
}
static CompletableFuture<Process> startProcessAndWaitForMatchedOutput(
ProcessBuilder processBuilder, String pattern, long waitForMillis) {
final CompletableFuture<Process> completableFuture = new CompletableFuture<>();
final Process process;
try {
process = processBuilder.start();
} catch (IOException ex) {
completableFuture.completeExceptionally(ex);
return completableFuture;
}
final Pattern compiledPattern = Pattern.compile(pattern);
final Timer timeoutTimer = setTimeout(() ->
completableFuture.completeExceptionally(new WaitForTimeExceededException()),
waitForMillis);
new Thread(() -> {
try (InputStream processOutputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(processOutputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String line;
/* The thread is blocked here.
Indeed the code call this method always return because
my completableFuture always completes.
But the problem is there is a running thread
which is a waste of resource. */
while ((line = bufferedReader.readLine()) != null) {
if (compiledPattern.matcher(line).matches()) {
completableFuture.complete(process);
timeoutTimer.cancel();
return;
}
}
completableFuture.completeExceptionally(new OutputDidNotMatchException());
timeoutTimer.cancel();
} catch (IOException ex) {
completableFuture.completeExceptionally(ex);
timeoutTimer.cancel();
}
}).start();
return completableFuture;
}
Правильно ли мое решение?Если нет, есть ли библиотеки, которые решают мою проблему?