# Erkennen, wann Prozess beendet ist, dann Thread beenden.



## Beatsleigher (20. Jan 2014)

Heyo Leute,

ich befasse mich derzeitig wieder mit dem Porten meines Programms Universal Android Toolkit von VB zu Java, und mir ist etwas sehr nerviges bei Java aufgefallen: Wenn man in Java einen externen Prozess starten möchte, wird dieser gar nicht beendet, selbst wenn der Prozess an sich schon längst tot ist - Java wartet einfach weiter.

Nun, mein Programm soll via ADB mit dem Android-Gerät kommunizieren, und das geht nun mal über ADB (Ich bin zu faul mir die einzelnen Ports zu merken, und dann Anweisungen via TCP zu senden).
Ich habe das Ganze schon in einem seperaten Thread laufen, damit der Benutzer weiterhin das Programm benutzen kann, jedoch, was nützt es dem Nutzer wenn er am Ende 5000 verschiedene Threads am Laufen hat, die unendlich viele Resourcen unnötig schlucken.


```
new Thread() {
                @Override
                public void run() {
                    try {
                        // Both jTextFields contain text.
                        ProcessBuilder process = new ProcessBuilder(adb.toString(), "push " + jTextField1.getText() + " " + jTextField2.getText());
                        Process pr = process.start();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
                        String line;
                        line = reader.readLine();
                        Date now = new Date();
                        if (!line.equals("")) {
                            jTextArea1.append("[" + now.toString() + "] " + line);
                        }

                    } catch (IOException/* | InterruptedException*/ ex) {
                        JOptionPane.showMessageDialog(null, "ERROR: Error while processing your request!\n" + ex.toString(), "Error Processing Request!", JOptionPane.ERROR_MESSAGE);
                    }
                }
            }.start();
```

Ich möchte irgendwie erkennen, dass der Prozess beendet ist, damit ich dann mit pr.destroy(); hinterhergehen kann, und das Ding dann ein und für alle Male "still legen" kann.

Ich habe schon mit pr.wait();, pr.waitFor(); und pr.exitVale(); rumprobiert, aber dann fängt er den Output des Programms nicht mehr.

Wie kann ich das am Besten lösen, am liebsten ohne Listener, aber wenn es nicht anders geht, geht es dann nicht anders.

Vielen Dank im Voraus.

EDIT:

Da war mal eie while-Schleife drin, die ich aber rausgenommen habe.


----------



## geqoo (20. Jan 2014)

Du meinst, wenn die Activity destroy't wird? Dafür gibt es mit Sicherheit einen Listener, der dieses Event abfangen kann.
Und dann musst du natürlich deine Thread-Handles irgendwo speicher, z.B.


```
Thread t1 = new Thread() { ... };
t1.start();
```

Wenn der Thread-Bezeichner immer gleich heißt, dann fügst du eben t1 jedes mal bei einem neuen Thread zu einer Liste hinzu und am Ende der Anwendung gehst du dann die Liste durch und hämmerst alle Threads weg


----------



## Beatsleigher (20. Jan 2014)

geqoo hat gesagt.:


> Du meinst, wenn die Activity destroy't wird? Dafür gibt es mit Sicherheit einen Listener, der dieses Event abfangen kann.
> Und dann musst du natürlich deine Thread-Handles irgendwo speicher, z.B.
> 
> 
> ...



Verstehe ich gerade nicht kannst. Könntest du das nochmal erläutern?


----------



## Lonsdaleit (22. Jan 2014)

Mit der Methode join() kannst du einen Thread (der für das Löschen anderer Threads zuständig ist) warten lassen, bis der Thread xyz beendet ist. Dann wird dieser (wieder) aktiv und löscht den Thread.

Ansonsten hast du mit isInterrupted() die Möglichkeit die Aktivität eines Threads zu überprüfen.

Ich hoffe, ich habe dich richtig verstanden und konnte helfen.


----------



## Beatsleigher (22. Jan 2014)

Lonsdaleit hat gesagt.:


> Mit der Methode join() kannst du einen Thread (der für das Löschen anderer Threads zuständig ist) warten lassen, bis der Thread xyz beendet ist. Dann wird dieser (wieder) aktiv und löscht den Thread.
> 
> Ansonsten hast du mit isInterrupted() die Möglichkeit die Aktivität eines Threads zu überprüfen.
> 
> Ich hoffe, ich habe dich richtig verstanden und konnte helfen.



Ja, danke. Das hat mir schon ein bisschen weitergeholfen, das Hauptproblem, jedoch, ist das der Prozess den ich aufrufe, nie beendet wird. Java läuft dann immer weiter.
kennst du da vllt. noch eine Lösung für?


----------



## kay73 (22. Jan 2014)

Der "Trick" ist, das Lesen von 
	
	
	
	





```
process.getInputStream)
```
 in einen Thread auszulagern und auf das Ende des Prozeses ganz normal mit 
	
	
	
	





```
process.waitFor()
```
 zu warten. Verwende einen ExecutorService anstatt Threads von Hand zu erzeugen und rufe 
	
	
	
	





```
shutdown()
```
 auf, damit die Anwendung normal terminiert. Das Stream-Kopieren kannst Du mit den Common-IOUtils auf einen Einzeiler reduzieren.


```
package test42;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProcessTest {

	public static void main(String[] args) throws IOException,
			InterruptedException {

		final ExecutorService newCachedThreadPool = Executors
				.newCachedThreadPool();

		final Process process = new ProcessBuilder("/bin/ls", "-la").start();

		final ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);

		newCachedThreadPool.submit(new Callable<Void>() {
			@Override
			public Void call() throws IOException {
				final InputStream is = process.getInputStream();
				final byte[] buffer = new byte[1024];
				int read = -1;
				do {
					read = is.read(buffer, 0, buffer.length);
					
					if (read > 0) {
						bos.write(buffer, 0, read);
					}
				} while (read != -1);
				return null;
			}
		});
		newCachedThreadPool.shutdown();

		int waitFor = process.waitFor();

		System.out.println(String.format("Exit code: %d. Output:\n%s", waitFor,
				new String(bos.toByteArray())));
	}
}
```


----------



## Beatsleigher (22. Jan 2014)

Danke an alle für eure Hilfe, aber ich habe es anders geregelt bekommen.
Der Grund, warum ich die Sachen in einen Thread haben wollte, ist der, dass der Benutzer gleich danach auch andere Sachen erledigen kann, z.B. wenn er gerade eine große Datei verschiebt, dann kann er sich ja auch gleich um andere (evtl.) wichtigere Dinge kümmern.

Ich habe es (zumindest für chmod) so gemacht:


```
appendLog("Chmod-ing binary (ADB)...");
        new Thread() {
            public void run() {
                try {
                    Process pr = new ProcessBuilder("/bin/chmod", "775 " + adb.toString()).start();
                    pr.waitFor();
                    appendLog("ADB has been made executable.");
                    interrupt();
                } catch (IOException | InterruptedException ex) {
                    appendLog("ERROR: Error while Chmod-ing binary (ADB)!");
                    appendLog(ex.toString());
                }
            }
        }.start();

/*
 * appendLog ist eine eigene Methode, mit der ich Text in der programm-eigenen Konsole anzeige,
 * mit Datum/Uhrzeit, etc.
*/
```


----------

