Java时间过长,如何成功销毁进程?
How to successfully destroy the process if it takes too much time in Java?
我正在使用 Process
从我的 Java 程序执行一个 shell 脚本,如果我的脚本需要很长时间,我想 kill/destroy 该过程。最好的方法是什么?
下面是我的代码:
public static void main(String[] args) throws IOException, InterruptedException {
// Your script
String script = "#!/bin/bash\n\necho \"Hello World\"\n\n readonly PARAM1=$param1\n echo $PARAM1\n\nreadonly PARAM2=$param2\n echo $PARAM2\n\n";
// create a temp file and write your script to it
File tempScript = File.createTempFile("temp_scripts_", "");
tempScript.setExecutable(true);
try (OutputStream output = new FileOutputStream(tempScript)) {
output.write(script.getBytes());
}
// build the process object and start it
List<String> commandList = new ArrayList<>();
commandList.add(tempScript.getAbsolutePath());
ProcessBuilder builder = new ProcessBuilder(commandList);
builder.redirectErrorStream(true);
builder.environment().put("param1", "abc");
builder.environment().put("param2", "xyz");
Process shell = builder.start();
// read the output and show it
try (BufferedReader reader = new BufferedReader(new InputStreamReader(shell.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// wait for the process to finish
// but I want to kill/destroy the process if it takes too much time
int exitCode = shell.waitFor();
// delete your temp file
tempScript.delete();
// check the exit code (exit code = 0 usually means "executed ok")
System.out.println("EXIT CODE: " + exitCode);
}
试试这样的东西:
long startTime = System.currentTimeMillis();
long endTime = start + 60*1000;
while (System.currentTimeMillis() < endTime)
{
// your code
}
据我所知,您目前正在无限期地等待结果,因为
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
由于 readline() 是阻塞操作,将阻塞。
天真的方法是将流中的读取外部化到自己的线程中,您可以随时中断它。
所以基本上你会有一个线程对象,它在它的构造函数中会得到适当的流和一个公共的 lockObject,然后在 运行() 方法中开始尝试从流中读取,并做任何事情你想处理数据。
在您的主线程中,您可以在启动脚本并获取所需的流后,构造这样一个线程实例并在其自己的线程中启动它。然后您将在主线程中等待第二个 "reader" 线程完成(这里的关键字是等待(超时),其中超时是脚本的最大(允许)运行 时间。
所以现在您的主线程正在等待您的 reader 线程完成它的任务,但最多 timeout 毫秒(或者是秒?)
在 wait(timeout) 之后,您可以终止脚本(如果它挂起,因为您设置的超时已过期)或者如果它正常退出则执行您想要的任何操作。
我知道没有包含实际代码,但该方法应该有效。
祝你好运
更新
class Process
没有带超时的 "waitFor" 方法,除非您使用 java 8. 作为替代方案,您可以尝试开始一个等待进程完成并使用 join(timeout)
.
加入此类线程的线程
以下是您的代码的概念证明,经过修改以使用线程:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
// Your script
String script = getScriptFromSomewhere();
// create a temp file and write your script to it
File tempScript = File.createTempFile("temp_scripts_", "");
tempScript.setExecutable(true);
try (OutputStream output = new FileOutputStream(tempScript)) {
output.write(script.getBytes());
}
// build the process object and start it
List<String> commandList = new ArrayList<>();
commandList.add(tempScript.getAbsolutePath());
ProcessBuilder builder = new ProcessBuilder(commandList);
builder.redirectErrorStream(true);
builder.environment().put("param1", "abc");
builder.environment().put("param2", "xyz");
Process shell = builder.start();
// Start the interrupting thread
long timeoutMillis = 5000;
ExecutingThread thread = new ExecutingThread(shell, timeoutMillis);
thread.start();
// read the output and show it
byte[] buffer = new byte[1024];
try (InputStream input = shell.getInputStream()) {
int read;
while ((read = input.read(buffer)) != -1) {
String text = new String(buffer, 0, read);
System.out.print(text);
}
}
// wait for the process to finish (or be interrupted)
thread.join();
if(!thread.isFinished()) {
System.out.println("PROCESS WAS INTERRUPTED");
} else {
// check the exit code (exit code = 0 usually means "executed ok")
System.out.println("PROCESS FINISHED, EXIT CODE: " + thread.getExitValue());
}
// delete your temp file
tempScript.delete();
}
}
class ExecutingThread extends Thread {
private long timeoutMillis;
private WaitingThread waitingThread;
public ExecutingThread(Process shell, long timeoutMillis) {
this.timeoutMillis = timeoutMillis;
this.waitingThread = new WaitingThread(shell);
}
@Override
public void run() {
waitingThread.start();
try {
waitingThread.join(timeoutMillis);
} catch (InterruptedException ignore) {
}
if(waitingThread.isAlive()) {
waitingThread.interrupt();
}
}
public int getExitValue() {
return waitingThread.getExitValue();
}
public boolean isFinished() {
return waitingThread.isFinished();
}
}
class WaitingThread extends Thread {
private Process shell;
private volatile int exitValue;
private volatile boolean finished = false;
public WaitingThread(Process shell) {
this.shell = shell;
}
@Override
public void run() {
try {
exitValue = shell.waitFor();
finished = true;
} catch (InterruptedException e) {
shell.destroy();
}
}
public int getExitValue() {
return exitValue;
}
public boolean isFinished() {
return finished;
}
}
我正在使用 Process
从我的 Java 程序执行一个 shell 脚本,如果我的脚本需要很长时间,我想 kill/destroy 该过程。最好的方法是什么?
下面是我的代码:
public static void main(String[] args) throws IOException, InterruptedException {
// Your script
String script = "#!/bin/bash\n\necho \"Hello World\"\n\n readonly PARAM1=$param1\n echo $PARAM1\n\nreadonly PARAM2=$param2\n echo $PARAM2\n\n";
// create a temp file and write your script to it
File tempScript = File.createTempFile("temp_scripts_", "");
tempScript.setExecutable(true);
try (OutputStream output = new FileOutputStream(tempScript)) {
output.write(script.getBytes());
}
// build the process object and start it
List<String> commandList = new ArrayList<>();
commandList.add(tempScript.getAbsolutePath());
ProcessBuilder builder = new ProcessBuilder(commandList);
builder.redirectErrorStream(true);
builder.environment().put("param1", "abc");
builder.environment().put("param2", "xyz");
Process shell = builder.start();
// read the output and show it
try (BufferedReader reader = new BufferedReader(new InputStreamReader(shell.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// wait for the process to finish
// but I want to kill/destroy the process if it takes too much time
int exitCode = shell.waitFor();
// delete your temp file
tempScript.delete();
// check the exit code (exit code = 0 usually means "executed ok")
System.out.println("EXIT CODE: " + exitCode);
}
试试这样的东西:
long startTime = System.currentTimeMillis();
long endTime = start + 60*1000;
while (System.currentTimeMillis() < endTime)
{
// your code
}
据我所知,您目前正在无限期地等待结果,因为
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
由于 readline() 是阻塞操作,将阻塞。
天真的方法是将流中的读取外部化到自己的线程中,您可以随时中断它。
所以基本上你会有一个线程对象,它在它的构造函数中会得到适当的流和一个公共的 lockObject,然后在 运行() 方法中开始尝试从流中读取,并做任何事情你想处理数据。
在您的主线程中,您可以在启动脚本并获取所需的流后,构造这样一个线程实例并在其自己的线程中启动它。然后您将在主线程中等待第二个 "reader" 线程完成(这里的关键字是等待(超时),其中超时是脚本的最大(允许)运行 时间。
所以现在您的主线程正在等待您的 reader 线程完成它的任务,但最多 timeout 毫秒(或者是秒?) 在 wait(timeout) 之后,您可以终止脚本(如果它挂起,因为您设置的超时已过期)或者如果它正常退出则执行您想要的任何操作。
我知道没有包含实际代码,但该方法应该有效。 祝你好运
更新
class Process
没有带超时的 "waitFor" 方法,除非您使用 java 8. 作为替代方案,您可以尝试开始一个等待进程完成并使用 join(timeout)
.
以下是您的代码的概念证明,经过修改以使用线程:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
// Your script
String script = getScriptFromSomewhere();
// create a temp file and write your script to it
File tempScript = File.createTempFile("temp_scripts_", "");
tempScript.setExecutable(true);
try (OutputStream output = new FileOutputStream(tempScript)) {
output.write(script.getBytes());
}
// build the process object and start it
List<String> commandList = new ArrayList<>();
commandList.add(tempScript.getAbsolutePath());
ProcessBuilder builder = new ProcessBuilder(commandList);
builder.redirectErrorStream(true);
builder.environment().put("param1", "abc");
builder.environment().put("param2", "xyz");
Process shell = builder.start();
// Start the interrupting thread
long timeoutMillis = 5000;
ExecutingThread thread = new ExecutingThread(shell, timeoutMillis);
thread.start();
// read the output and show it
byte[] buffer = new byte[1024];
try (InputStream input = shell.getInputStream()) {
int read;
while ((read = input.read(buffer)) != -1) {
String text = new String(buffer, 0, read);
System.out.print(text);
}
}
// wait for the process to finish (or be interrupted)
thread.join();
if(!thread.isFinished()) {
System.out.println("PROCESS WAS INTERRUPTED");
} else {
// check the exit code (exit code = 0 usually means "executed ok")
System.out.println("PROCESS FINISHED, EXIT CODE: " + thread.getExitValue());
}
// delete your temp file
tempScript.delete();
}
}
class ExecutingThread extends Thread {
private long timeoutMillis;
private WaitingThread waitingThread;
public ExecutingThread(Process shell, long timeoutMillis) {
this.timeoutMillis = timeoutMillis;
this.waitingThread = new WaitingThread(shell);
}
@Override
public void run() {
waitingThread.start();
try {
waitingThread.join(timeoutMillis);
} catch (InterruptedException ignore) {
}
if(waitingThread.isAlive()) {
waitingThread.interrupt();
}
}
public int getExitValue() {
return waitingThread.getExitValue();
}
public boolean isFinished() {
return waitingThread.isFinished();
}
}
class WaitingThread extends Thread {
private Process shell;
private volatile int exitValue;
private volatile boolean finished = false;
public WaitingThread(Process shell) {
this.shell = shell;
}
@Override
public void run() {
try {
exitValue = shell.waitFor();
finished = true;
} catch (InterruptedException e) {
shell.destroy();
}
}
public int getExitValue() {
return exitValue;
}
public boolean isFinished() {
return finished;
}
}