我需要运行一些bash命令,每个命令大约需要18个小时才能完成。为了使用所有可用的CPU核,我使用以下代码在单独的线程上运行每个命令。然而,线程在大约5小时的工作后停止做任何事情。我知道通过检查cpu使用情况。当我使用相同的代码只运行一个命令时它运行正常。我还在不同的bash终端会话中运行了几个命令,以确保它们真正独立。
public class RunBashCommand implements Runnable{
private String[] command; // e.g. {"bash", "myScript.sh", "arg1", arg2"}
private String fSSubjectFolder;
private String subjectId;
RunBashCommand ( String[] newCommand, String newSubjectFolder, String newSubjectId ) {
command = newCommand;
fSSubjectFolder = newSubjectFolder;
subjectId = newSubjectId;
}
public void run ( ){
runCommand ();
}
private void runCommand (){
Runtime run = Runtime.getRuntime();
Process p;
try {
String line;
p = run.exec(command);
BufferedReader buf = new BufferedReader( new InputStreamReader(p.getInputStream() ) );
PrintWriter pw = new PrintWriter( new File( fSSubjectFolder+"/"+subjectId+"CTPFS.log" ) );
while ( ( line = buf.readLine() ) != null ){
pw.println( line );
}
p.waitFor();
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
并且在调用此类的父线程中,我有:
while (commandList.size()>0) {
String[] command = commandList.get(commandList.size()-1); // FILO queue
Runnable runBash = new RunBashCommand( command, "folderAddress1", "folderAddress2" );
Thread runBashThread = new Thread ( runBash );
runBashThread.setName ( "some name" );
runBashThread.start();
RunCTPFS.threads.add(runBashThread); // my thread list for thread tracking
commandList.remove(commandList.size()-1);
}
任何帮助都将非常感激。我怀疑饥饿。
答案 0 :(得分:2)
你的bash脚本是否在stderr上产生任何输出?看起来你正在通过getInputStream()
阅读它的标准输出,但是你没有对getErrorStream()
做任何事情。如果你没有读取stderr,那么如果stderr缓冲区填满,进程可能会挂起。
调用进程时的最佳做法是在单独的线程中读取stdout和stderr。您必须以并行线程读取它们以避免阻塞。
您不需要为exec()
分别拥有单独的Java线程。每个exec()
调用将启动一个单独的进程,该进程在单独的执行线程中执行。单独的Java线程不会给你带来什么。您可以从单个线程执行所有exec()
次调用。
我的建议:从单个线程启动所有进程。对于您收到的每个Process
对象,启动两个后台线程:一个用于处理stdout,一个用于处理stderr。然后在原始线程中,您可以在循环中对每个进程执行waitFor()
。
List<Process> processes = new ArrayList<>();
for (String command: commands) {
Process process = Runtime.getRuntime().exec(command);
(new BackgroundReaderThread(process.getInputStream())).start();
(new BackgroundReaderThread(process.getErrorStream())).start();
processes.add(process);
}
for (Process process: processes) {
process.waitFor();
}