[英]how to kill runtime.exec?
我在jframe中使用以下代码,以便通过java程序执行shell脚本,但是当我实现另一种方法来停止运行过程时,该方法首先被阻止,并且我无法停止程序。 所以我想杀死新进程,问题是如何获取进程的pid以及如何将其置于后台以杀死它。
public static void execShellCmd(String cmd) {
try {
testPath = getPath();
System.out.println(cmd);
Runtime runtime = Runtime.getRuntime();
process = runtime.exec(new String[] { "sh",
testPath + "/install.sh", cmd, "&" });
int exitValue = process.waitFor();
value = exitValue;
System.out.println("exit value: " + exitValue);
BufferedReader buf = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = "";
BufferedWriter bufferedWriter = null;
while ((line = buf.readLine()) != null) {
System.out.println("exec response: " + line);
log = line;
writeToFile(line);
}
} catch (Exception e) {
System.out.println(e);
}
}
如果您的“其他方法”可以访问原始exec
返回的Process
对象,则只需调用process.destroy()
即可终止正在运行的进程。 您不需要知道本机PID。 这是一个使用SwingWorker的或多或少的完整示例(可能我忘记了一些try / catch块):
private Process runningProcess = null;
public static void execShellCmd(String cmd) {
if(runningProcess != null) {
// print some suitable warning about process already running
return;
}
try {
testPath = getPath();
System.out.println(cmd);
Runtime runtime = Runtime.getRuntime();
runningProcess = runtime.exec(new String[] { "sh",
testPath + "/install.sh", cmd });
new SwingWorker<Integer, Void>() {
protected Integer doInBackground() {
// read process output first
BufferedReader buf = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = "";
while ((line = buf.readLine()) != null) {
System.out.println("exec response: " + line);
log = line;
writeToFile(line);
}
// only once we've run out of output can we call waitFor
while(true) {
try {
return runningProcess.waitFor();
} catch(InterruptedException e) {
// do nothing, wait again
} finally {
Thread.interrupted();
}
}
return -1;
}
protected void done() {
runningProcess = null;
}
}.execute();
}
}
public static void stopProcess() {
if(runningProcess != null) {
runningProcess.destroy();
}
}
只要execShellCmd
事件分发线程中调用execShellCmd
和stopProcess
,就无需同步,因为对runningProcess
字段的所有访问都发生在同一线程上( SwingWorker
是doInBackground
发生在工作线程上,但done
运行在EDT)。
为此,您可以使用java.util.concurrent中存在的功能
在包含UI的现有类中,您必须添加类似以下内容:
//class variable to store the future of your task
private Future<?> taskFuture = null;
//to be called from button "Start" action handler
public void actionStart() {
//don't double start, if there is one already running
if(taskFuture == null || taskFuture.isDone()) {
//create the new runnable instance, with the proper commands to execute
MyShellExecutor ex = new MyShellExecutor(new String[] { "sh",testPath + "/install.sh", cmd, "&" });
//we only need one additional Thread now, but this part can be tailored to fit different needs
ExecutorService newThreadExecutor = Executors.newSingleThreadExecutor();
//start the execution of the task, which will start execution of the shell command
taskFuture = newThreadExecutor.submit(ex);
}
}
//to be called from button "Stop" action handler
public void actionStop() {
//if not already done, or cancelled, cancel it
if(taskFuture !=null && !taskFuture.isDone()) {
taskFuture.cancel(true);
}
}
完成这项工作的主要组件是Runnable
,我将其命名为MyShellExecutor
,如下所示:
public class MyShellExecutor implements Runnable {
//stores the command to be executed
private final String[] toExecute;
public MyShellExecutor(String[] toExecute) {
this.toExecute=toExecute;
}
public void run() {
Runtime runtime = Runtime.getRuntime();
Process process = null;
try {
process = runtime.exec(toExecute);
int exitValue = process.waitFor();
System.out.println("exit value: " + exitValue);
BufferedReader buf = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = buf.readLine()) != null) {
System.out.println("exec response: " + line);
//do whatever you need to do
}
} catch (InterruptedException e) {
//thread was interrupted.
if(process!=null) { process.destroy(); }
//reset interrupted flag
Thread.currentThread().interrupt();
} catch (Exception e) {
//an other error occurred
if(process!=null) { process.destroy(); }
}
}
}
注意:运行耗时的操作时,请确保不要在UI线程上执行此操作。 这只会阻塞用户,而不能提供良好的用户体验。 始终执行可能使用户等待其他线程的操作。
推荐阅读: Java并发实践
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.