运行几个小时后我的线程停止了

时间:2013-09-09 00:21:27

标签: java multithreading multiprocessing

我需要运行一些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);
}

任何帮助都将非常感激。我怀疑饥饿。

1 个答案:

答案 0 :(得分:2)

  1. 你的bash脚本是否在stderr上产生任何输出?看起来你正在通过getInputStream()阅读它的标准输出,但是你没有对getErrorStream()做任何事情。如果你没有读取stderr,那么如果stderr缓冲区填满,进程可能会挂起。

    调用进程时的最佳做法是在单独的线程中读取stdout和stderr。您必须以并行线程读取它们以避免阻塞。

  2. 您不需要为exec()分别拥有单独的Java线程。每个exec()调用将启动一个单独的进程,该进程在单独的执行线程中执行。单独的Java线程不会给你带来什么。您可以从单个线程执行所有exec()次调用。

  3. 我的建议:从单个线程启动所有进程。对于您收到的每个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();
    }