Einen Prozess mit Java beenden

71

Ich würde gerne wissen, wie man einen Prozess "tötet", der gestartet wurde. Ich kenne die Prozess-API, bin mir aber nicht sicher, ob ich damit einen bereits ausgeführten Prozess wie Firefox.exe usw. "beenden" kann. Wenn die Prozess-API verwendet werden kann, können Sie mich bitte auf die verweisen richtige Richtung? Wenn nicht, welche anderen Optionen stehen zur Verfügung? Vielen Dank.

Jeel Shah
quelle
Java läuft in einer virtuellen Maschine, es ist wie eine geschlossene Box; Auf keinen Fall beenden Sie einen Systemprozess in reinem Java. Möglicherweise gibt es Optionen, die native Schnittstellen aufrufen. Siehe JNI oder JNA
digitale Illusion
Welcher Trick hat Ihr Problem gelöst? Ich stehe auch vor dem gleichen Problem. Ich habe Details hier beschrieben: stackoverflow.com/questions/27942679/…
Bilal Ahmed Yaseen
1
@BilalAhmedYaseen Ich habe die ausgewählte Antwort und die Antwort von Lakshitha Ranasingha verwendet, sie haben den Trick für mich getan.
Jeel Shah

Antworten:

58

Wenn Sie den Prozess mit in Ihrer Java-Anwendung starten (z. B. durch Aufrufen von Runtime.exec()oder ProcessBuilder.start()), haben Sie einen gültigen ProcessVerweis darauf und können die destroy()Methode in aufrufenProcess Klasse , um diesen bestimmten Prozess abzubrechen.

Beachten Sie jedoch, dass der von Ihnen aufgerufene Prozess möglicherweise nicht beendet wird, wenn neue Unterprozesse erstellt werden (siehe http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4770092) ).

Wenn Sie jedoch externe Prozesse beenden möchten (die Sie nicht aus Ihrer Java-App erstellt haben), können Sie auch O / S-Dienstprogramme aufrufen, mit denen Sie dies tun können. Sie können beispielsweise unter Unix / Linux einen Befehl Runtime.exec()on versuchen killund nach Rückgabewerten suchen , um sicherzustellen, dass die Anwendung beendet wurde oder nicht (0 bedeutet Erfolg, -1 bedeutet Fehler). Aber das macht Ihre Anwendungsplattform natürlich abhängig.

Yohan Liyanage
quelle
Ich stehe auch vor dem gleichen Problem. Ich habe Details hier beschrieben: stackoverflow.com/questions/27942679/…
Bilal Ahmed Yaseen
Und denken Sie daran, dass Sie normalerweise Administratorrechte benötigen, um einen Prozess abzubrechen. Vielleicht möchten Sie in Ihrer Antwort auch den Windows-Befehl hinzufügen, um dies zu tun.
PhoneixS
61

Unter Windows können Sie diesen Befehl verwenden.

taskkill /F /IM <processname>.exe 

Um es gewaltsam zu töten, können Sie verwenden;

Runtime.getRuntime().exec("taskkill /F /IM <processname>.exe")
Laksitha Ranasingha
quelle
32

AFAIU java.lang.Process ist der von Java selbst erstellte Prozess (wie Runtime.exec ('Firefox')).

Sie können systemabhängige Befehle wie verwenden

 Runtime rt = Runtime.getRuntime();
  if (System.getProperty("os.name").toLowerCase().indexOf("windows") > -1) 
     rt.exec("taskkill " +....);
   else
     rt.exec("kill -9 " +....);
chro
quelle
Funktioniert unter Win7 64 Bit: D
Broken_Window
8
Für Linux habe ich "pkill Firefox" verwendet
Rajendra Thorat
2
"kill -9" ist nicht immer eine gute Idee, da es dem getöteten Prozess keine Chance gibt, sauber herunterzukommen.
Jerome Provensal
@ JeromeProvensal Was ist, wenn Sie ein Antivirenprogramm erstellen? Sie nicht wollen , das Virus eine Chance zu geben , sauber zu kommen!
Khushraj Rathod
1
@ Holyprogrammer, stimmte zu, aber ich sprach nicht über einen Virus, sondern über einen Prozess, den Sie kontrollieren / verstehen.
Jerome Provensal
10

Mit Java 9können wir ProcessHandle verwenden, mit dem sich native Prozesse leichter identifizieren und steuern lassen:

ProcessHandle
  .allProcesses()
  .filter(p -> p.info().commandLine().map(c -> c.contains("firefox")).orElse(false))
  .findFirst()
  .ifPresent(ProcessHandle::destroy)

wo "Firefox" ist der Prozess zu töten.

Diese:

  • Listet zunächst alle auf dem System ausgeführten Prozesse als auf Stream<ProcessHandle>

  • Filtert diesen Stream faul, um nur Prozesse zu behalten, deren gestartete Befehlszeile "Firefox" enthält. Beide commandLineoder commandkönnen verwendet werden, je nachdem, wie der Prozess abgerufen werden soll.

  • Findet den ersten gefilterten Prozess, der die Filterbedingung erfüllt.

  • Und wenn mindestens eine Prozessbefehlszeile "Firefox" enthielt, wird sie mit beendet destroy.

Kein Import erforderlich, da ProcessHandleein Teil von java.lang.

Xavier Guihot
quelle
4

Aus Versehen bin ich auf eine andere Möglichkeit gestoßen, einen Force-Kill unter Unix durchzuführen (für diejenigen, die Weblogic verwenden). Dies ist billiger und eleganter als das Ausführen von / bin / kill -9 über Runtime.exec () .

import weblogic.nodemanager.util.Platform;
import weblogic.nodemanager.util.ProcessControl;
...
ProcessControl pctl = Platform.getProcessControl();
pctl.killProcess(pid);

Und wenn Sie Schwierigkeiten haben, die PID zu erhalten, können Sie die Reflexion auf java.lang.UNIXProcess verwenden , z.

Process proc = Runtime.getRuntime().exec(cmdarray, envp);
if (proc instanceof UNIXProcess) {
    Field f = proc.getClass().getDeclaredField("pid");
    f.setAccessible(true);
    int pid = f.get(proc);
}
Chukko
quelle
Es gibt eine plattformübergreifende Methode, um PID für jede JVM-Anwendung zu erhalten. Überprüfen Sie meistens-über-java.blogspot.co.uk
Espinosa
@Brian Gordon Ja, ich weiß, die Verwendung von sun.jvmstat.monitor. * Ist auch keine perfekte Lösung, nicht Teil der unterstützten öffentlichen Schnittstelle, aber immer noch besser und portabler als externe Unix-Tools oder die Erwartung, dass Process UNIXProcess ist. was es unter Windows nicht ist und vielleicht auch in Zukunft nicht sein wird Java Release 7 unter Unix.
Espinosa
@Espinosa Kommt darauf an, was du erreichen willst. destroy () unter Windows erzwingt das Töten, daher wird dieser Hack dort nicht benötigt (und übrigens hat Weblogic auch eine Klasse für Windows). Denken Sie daran, dass wir solch hässlichen Code nur wegen kurzsichtiger JVM-Implementierung und API-Designfehlern schreiben müssen.
Chukko
Fortsetzung: Am Ende ist es nur Geschmackssache - für Java Process Manager würde ich vielleicht Ihre Lösung verwenden - aber um einen bestimmten Fehler zu umgehen, bevorzuge ich einen kleineren / schnelleren / schmutzigeren "Patch" von mir gegenüber Ihrer theoretisch saubereren, aber iterativen und umständlicheren Lösung . Jeder Nagel benötigt einen anderen Hammer.
Chukko
3

Es könnte ein Java-Interpreter-Defekt sein, aber Java unter HPUX führt keinen Kill -9 aus, sondern nur einen Kill -TERM.

Ich habe einen kleinen Test gemacht testDestroy.java:

ProcessBuilder pb = new ProcessBuilder(args);
Process process = pb.start();
Thread.sleep(1000);
process.destroy();
process.waitFor();

Und die Anrufung:

$ tusc -f -p -s signal,kill -e /opt/java1.5/bin/java testDestroy sh -c 'trap "echo TERM" TERM; sleep 10'

stirbt nach 10s (nicht wie erwartet nach 1s getötet) und zeigt:

...
[19999]   Received signal 15, SIGTERM, in waitpid(), [caught], no siginfo
[19998] kill(19999, SIGTERM) ............................................................................. = 0
...

Dasselbe unter Windows zu tun, scheint den Prozess auch dann zu beenden, wenn das Signal verarbeitet wird (dies kann jedoch daran liegen, dass Windows keine Signale zum Zerstören verwendet).

Eigentlich fand ich Java - Process.destroy () Quellcode für Linux- bezogene Thread- und Openjava-Implementierung scheint auch -TERM zu verwenden, was sehr falsch zu sein scheint.

Chukko
quelle
1
Die Verwendung von -TERM ist korrekt, da der Prozess dadurch nach sich selbst bereinigt werden kann. Die Verwendung von kill -9 macht das arme Ding nur kaputt. Der wirklich richtige Weg ist, kill -TERM zu verwenden, einige Zeit zu warten und dann -9 zu töten, wenn es noch da ist.
Urban Vagabond
1
Ja - aber JVM gibt leider keinen folgenden Kill -9 aus, sodass Sie den Kill nicht erzwingen können. Also immer noch sehr falsch. Es sollte eine Force-Option geben, andernfalls ist dies nur für gut verhaltene Prozesse nützlich - dh nur für sonnige Tage.
Chukko
1
Wird nicht destroyForcibly()gesendet kill -9?
Ondra Žižka
In der Tat - obwohl es nur in Java 8 verfügbar ist (was für das Projekt, für das ich entwickelt habe, nicht verfügbar war). Mir ist gerade aufgefallen, dass Haysa Rodrigues diese Antwort bereits hinzugefügt hat.
Chukko
3

Versuch es:

String command = "killall <your_proccess>";
Process p = Runtime.getRuntime().exec(command);
p.destroy();

Wenn der Prozess noch läuft, fügen Sie hinzu:

p.destroyForcibly();
Haysa Rodrigues
quelle
Muss
Nach Runtime.execder Rückkehr wissen Sie nicht, wie weit der killallProzess fortgeschritten ist, und töten dann sofort die killall, vielleicht bevor sie die Möglichkeit hatte, etwas zu tun. Stattdessen destroysollten Sie es lieber waitFor()und seinen Exit-Status überprüfen.
EndlosSchleife
1

Sie können einen (SIGTERM) Windows-Prozess beenden, der von Java aus gestartet wurde, indem Sie die destroy-Methode für das Process-Objekt aufrufen. Sie können auch alle untergeordneten Prozesse beenden (seit Java 9).

Der folgende Code startet eine Batch-Datei, wartet zehn Sekunden, beendet dann alle Unterprozesse und beendet schließlich den Batch-Prozess selbst.

ProcessBuilder pb = new ProcessBuilder("cmd /c my_script.bat"));
Process p = pb.start();
p.waitFor(10, TimeUnit.SECONDS);

p.descendants().forEach(ph -> {
    ph.destroy();
});

p.destroy();
Jamie Lister
quelle