2011-09-19 5 views
6

Używam procesora Java ProcessBuilder do uruchomienia podprocesu, który jest innym programem Java, który musi działać w oddzielnej maszynie JVM.Podproces uruchamiany z języka Java kończy się za pomocą waitFor, ale strumienie nie są zakończone.

Uruchamiam dwa wątki, aby odczytać strumienie standardowe i stderr z procesu, aby nie było zawieszania się, jeśli bufory strumieniowe są pełne. Wywołanie Process.waitFor zwraca, ale strumienie nie są zakończone.

Kod używam wygląda mniej więcej tak (polecenia jest listą ciągów):

ProcessBuilder pb = new ProcessBuilder(command); 

final Process p = pb.start(); 
final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 
final ByteArrayOutputStream errStream = new ByteArrayOutputStream(); 

Thread outputThread = new Thread() { 
    @Override 
    public void run() { 
     try { 
      IOUtils.copy(p.getInputStream(), outStream); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    }; 
}; 
outputThread.start(); 

Thread errorThread = new Thread() { 
    @Override 
    public void run() { 
     try { 
      IOUtils.copy(p.getErrorStream(), errStream); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    }; 
}; 
errorThread.start(); 

int returncode = p.waitFor(); 
outputThread.join(); 
errorThread.join(); 

Jeśli uruchomię coś innego, takich jak „java -version” lub „dir”, czy coś, az kodu działa w porządku. Mam dostęp do kodu Java, który próbuję uruchomić, ale nigdy nie słyszałem, aby wywołać metodę close() w System.out.

+0

Możesz być zainteresowany w moim pytaniem o zamknięcie procesu strumieni odpowiednio: http://stackoverflow.com/questions/7065067/how-to-close-std -streams-from-java-lang-process-odpowiedni Kolejny przydatny link: http://mark.koli.ch/2011/01/leaky-pipes-remember-to-close-your-streams-when-using- javas-runtimegetruntimeexec.html –

+0

Jeśli używam 'IOUtils.closeQuietly' lub nawet wywołuję' close() 'na strumieniach przed wywołaniami' join() ', program zawiesza się na tym wywołaniu. –

+0

Jest tak prawdopodobnie dlatego, że 'IOUtils.copy (in, out)' używa 'InputStream.read (byte [])' i to blokuje i czeka na przychodzące dane. Dlatego wątki działają wiecznie i dlatego 'join()' czeka na zawsze. Musisz wymusić zamknięcie tutaj po przekroczeniu określonego czasu. Proszę wypróbować taką implementację, jak ta, którą zamieściłem w mojej odpowiedzi z linku, który ci podałem. Założę się, że da sobie z tym radę. –

Odpowiedz

0

Jak wiem z this website, musisz sam zamykać wszystkie strumienie std z obiektu Process. Bez względu na to, czy jest używany przed, czy nie. Wydaje się to bardzo związane z G1 odśmiecaczem śmieci (domyślnie od Java 7 afaik), który utrzymuje otwarte rury, gdy nie są zamknięte jawnie - nawet wtedy, gdy kończy się podproces.

Nie jestem zaznajomiony z internals tutaj, ale kod napisałem w my answer na moje pytanie działa dobrze na systemie 24/7 dzwoniąc GhostScript i inni dużo.

Inne pytania i odpowiedzi dotyczące SO stwierdzając, że należy zamknąć proces STD-strumienie wyraźne:

Powiązane problemy