2009-08-05 10 views
2

Laissez-moi d'abord dire que mon expérience avec le filetage est assez faible.Question de threading Java - l'écoute de n flux d'erreurs

J'ai une application qui démarre plusieurs autres fichiers Java via la méthode Runtime.exec. Le problème est que les fichiers JAR démarrés doivent être exécutés simultanément, mais pour obtenir le flux d'erreurs des fichiers JAR démarrés, vous devez avoir une boucle «Assis et écoutée» jusqu'à la fin du processus.

C'est ce que j'ai maintenant:

_processes.add(Runtime.getRuntime().exec(commandList.toArray(new String[ commandList.size() ]))); 
Thread thread = new Thread(new Runnable() { 
    private final int _processNumber = _processes.size() - 1; 
    public void run() { 
     String streamData = _processNumber + " : "; 
     streamData += "StdError [\r"; 
     BufferedReader bufferedReader = 
       new BufferedReader(new InputStreamReader(_processes.get(_processNumber).getErrorStream())); 
     String line = null; 
     try { 
      while ((line = bufferedReader.readLine()) != null) { 
       streamData += line + "\r"; 
      } 
      bufferedReader.close(); 
      streamData += "]\r"; 
      LOG.error(streamData); 
     } 
     catch (Exception exception) { 
      LOG.fatal(exception.getMessage()); 
      exception.printStackTrace(); 
     } 
    } 
}); 
thread.start(); 

Quelqu'un peut-il expliquer comment obtenir le « flux erreur threads d'écoute » pour fonctionner correctement?

TIA

Répondre

0

Il y a un très bon tutoriel here sur la façon d'utiliser Runtime.exec(). Lisez-y tout, mais en particulier jetez un oeil à la page 4 où il explique comment utiliser un 'StreamGobbler' s'exécutant dans un thread séparé pour consommer les flux std out et std err du processus en cours d'exécution.

Fondamentalement, ce que vous devriez chercher à mettre en œuvre dans le code pseduo est:

Runtime rt1 = Runtime.getRuntime().exec("my command") 
new StreamGobbler(rt1.getOutputStream()).start() 
new StreamGobbler(rt1.getErrorStream()).start() 
//repeat for each external process (rt2, rt3 etc) 
... 
rt1.waitFor() 
rt2.waitFor() 
rt3.waitFor() 

à savoir vous lancez chaque processus et commencez immédiatement à consommer la sortie de chaque processus dans un fil séparé. Avec les threads consommateurs démarrés, attendez que chaque processus se termine et retourne.

+0

Oui, j'ai déjà lu ceci. Le problème est que rt1 ouvre une socket d'écoute et que rt2 ouvre le côté write du socket. Si je démarre 2 threads pour se nourrir des flux de rt1, le thread parent semble bloquer et rt2 ne démarre jamais. J'ai essayé d'exécuter toutes les commandes exec et ensuite de démarrer tous les écouteurs et quand je le fais cela force les commandes exec à bloquer. – javamonkey79

1

Au lieu d'utiliser Runtime.getRuntime() exec(), utilisez Process pour lancer des processus externes .. Il va vous rendre la vie beaucoup plus facile ..

code Exemple d'un projet de la mine.

//Build command 
    List<String> commands = new ArrayList<String>(); 
    commands.add("my_application"); 
    commands.add("arg1"); 
    commands.add("arg2"); 
    log.debug("{}", commands); 

    //Run command with arguments 
    ProcessBuilder pb = new ProcessBuilder(commands); 
    pb.directory(directory); 
    pb.redirectErrorStream(true); 
    Process process = pb.start(); 

    //Read output 
    StringBuilder out = new StringBuilder(); 
    BufferedReader br = new BufferedReader(new InputStreamReader 
     (process.getInputStream())); 

    //Only log unique lines (you might not need this) 
    String line = null, previous = null; 
    while ((line = br.readLine()) != null) 
     if (!line.equals(previous)) { 
      previous = line; 
      out.append(line).append('\n'); 
      log.debug(line); 
     } 

    //Check result 
    if (process.waitFor() == 0) 
     return 0; 

    //Abnormal termination: Log command parameters and output and throw ExecutionException 
    log.error("{}", commands); 
    log.error("\n{}", out.toString()); 
    throw new ExecutionException(new IllegalStateException("MyApplication exit code 1")); 
+0

Je pense que la concurrence des threads engendrés et de leurs flux correspondants est le problème ici. Je ne vois pas grand chose dans ProcessBuilder (ou d'ailleurs dans tout Java) qui gère beaucoup mieux les processus. jconfig est mentionné dans l'article ci-dessus mais apparemment le projet est à peu près mort (du moins pour l'instant). – javamonkey79

+0

Est-ce que PipedOut/InputStream serait utile ici? – Tim