Ich möchte in einem anderen Java-Programm mittels Runtime.getRuntime().exec("java -jar prog.jar"); ein Jar File starten. Nun kann es aber schon sein, das der Benutzer die Jar prog.jar bereits vorher manuell gestartet hat. Wie kann ich denn prüfen ob eine Instanz von prog.jar bereits läuft, da ich es nicht doppelt starten sollte?
Besten Dank fürs lesen und nochmehr fürs antworten ...
ich würde dir empfehlen beim start von prog eine file zu erstellen und beim beenden diese wieder zu löschen => ist die file am anfang schon da dann wirfst du ne exception
Ich könnte wie du geschrieben hast ein File erstellen und prüfen ob es da ist. Aber wohin erstellen? In das Lokale Verzeichnis? Was ist wenn das Jar File in zwei unterschiedlichen Ordner existiert? Oder pauschal nach c:\? Was ist dann mit Linux Systemen?
Gibt es keine alternativen? Wenn auch etwas aufwendiger?
kommt auf dein Programm an. Wenn du einen Installationsordner mit Configdateien im user.home hast kannst du die Datei dort speichern. Ansonsten bieten die die tmp Ordner an ( /tmp unter Linux, bei Windows gibts auch so was irgendwo unter "..../Dokumente und Einstellungen").
mit System.getProperty(String) , die möglichen Informationen zur Abfrage findest du z.B. hier:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#getProperties()
das Speichern in /tmp hat den Vorteil, dass die Datei bei einem Reboot automatisch gelöscht wird, d.h. sollte dein Programm mal unerwartet beendet werden und die lock Datei deshalb nicht korrekt gelöscht werden (Stromausfall, etc...) ist nach einem Reboot alles wieder beim alten.
/**
* Ermitteln, ob das Programm bereits gestartet ist
*
* @param filename Dateiname
*
* @return true, falls das Programm bereits gestartet ist
*/
public boolean isOtherInstanceRunning(String filename) {
try {
File f = new File(System.getProperty("java.io.tmpdir") + "/" + filename + ".lock");
fos = new FileOutputStream(f);
fc = fos.getChannel();
lock = fc.tryLock();
if (lock == null) {
fc.close();
fos.close();
return true;
}
f.deleteOnExit();
} catch (Exception e) {
return false;
}
return false;
}
das läuft bei mir prima. nur mit datei erstellen können fehler entstehen, da das programm ja auch abschmieren kann und die datei dann immernoch existiert.
das läuft bei mir prima. nur mit datei erstellen können fehler entstehen, da das programm ja auch abschmieren kann und die datei dann immernoch existiert.
Für den Fall das die Datei gefunden wird, kann man den Nutzer ja Fragen ob er das Programm trotzdem starten möchte (das ist das Verhalten was die meisten Programme haben, z.B. Opera bei mir gestern als ich ausversehen über das Netzkabel gestolpert bin (Notebook ohne eingebautem Akku), Opera speichert in ~/.opera). /tmp ist aber wie gesagt nach dem Reboot sowieso wieder leer (wird bei der Windowsvariante ja genauso sein).
Die API empfiehlt bei File.deleteOnExit() die Methode nicht in Kombination mit FileLock zu benutzen und die Datei wird bei mir auch nicht gelöscht. Wie kann man eine locked File löschen?
Zum Thema Files: Schon mal überlegt wie zeitkritisch das ist? Ich habe da Befürchtungen, dass das nicht in allen Fällen zuverlässig funktioniert.
Einfach mal so eine Idee - Interprozesskommunikation:
Der Prozess B richtet einen Socket ein - prüft aber erst ob der schon aktiv ist (dann läuft schon eine Instanz des Prozesses B)
Der Prozess A versucht über den Socket zu kommunizieren und wenn das nicht geht, startet er B.
Das müsste doch funktionieren. (die Versuche die wir im NDS gemacht haben sind zu lange her.)
Wie sich diese Idee im zeitkritischen Umfeld verhält weiss ich allerdings auch nicht.
Momentchen bitte...ich hab nur fix gegooglet, sind denn sockets nicht eher was für Netzwerkgeschichten? Wenn ich das richtig verstanden habe, ist die Idee, einen Socket zu erstellen, den man für nichts weiter nutzt, als zur Existenzabfrage? Kann es da nicht Probleme mit etwaig feindseeligen Firewall-Einstellungen geben? Mir schmeckte die Lösung so nicht. Man muss doch nen lock, wie er oben erzeugt wurde, mit einer anderen Methode auch wieder aufheben können, finde ich.
Ja Sockets sind eine Netzwerkgeschichte sie eignen sich eben für Interprozesskommunikation
Firewalleinstellungen auf localhost? (Die beiden werden ja auf demselben Rechner laufen denke ich)
Ansonsten ist port 80 immer offen ......
Einen lock aufheben? Da müssen jetzt andere Antworten, aber ich glaube ein socket verschwindet nach einem Prozessabsturz eher als ein File.
Ich hab die Idee auch geäussert um vielleicht von jemandem der es besser weiss als ich ein "Bravo" oder eine vernichtende Kritik zu lesen
Wie schon erwähnt kanns zu Problemen kommen wenn man sich allein auf ein Filelock verlässt (File wurde beim beenden nciht gelöscht).
Auch Sockets wurden ja bereits erwähnt. Wenn man beide Verfahren kombiniert bekommt man ein relativ akurates Verfahren das sogut wie immer funktioniert.
Instanz A schaut nach ob ein bestimmtes lockfile existiert. Wenn ja dann steht in der Datei ein Port drin auf dem das konkurrenzprogramm B erreicht werden kann. Wenn diese kommunikation dann gelingt läuft Instanz B schon und A kann sich beenden.
Kann Instanz A auf dem Port in der Datei niemanden erreichen kann er davon ausgehen dass das Programm noch nicht läuft. Instanz A erstellt auf dem Port einen Socket und sagt damit dass es läuft. Ist der Port belebt weicht Instanz A auf einen anderen Port aus und ändert die lockdatei entsprechend.
Bis auf den Fall dass der user per hand das lockfile löscht sollten damit alle Fälle abgedeckt sein.
Eieiei...wie bring ich euch das jetzt schonend bei? Ich habe den FileLock, File und FileOutputStream in einer Variablen gespeichert und auf diesen dann FileLock.realease und FOS.close und File.delete() aufgerufen brachte Erfolg. Das mit den Sockets muss ich erst noch schakkern...dauert beim noobadix immer n bisschen. Mein Fehler war, dass ich static irgendwie mit final vewechselt habe. Hier die Korrektur für den obigen Ansatz, wie ich sie gebrauche:
Der Ansatz funktioniert aber auch nur wenn die Anwendung auf normalem Weg beendet wird. Schmiert das Programm mal ab und das Lockfile wird nicht gelöscht wars das erstmal
Wenn das Lockfile da ist, aber der Port nicht, kann doch das Lockfile gelöscht werden ....
Na ja, vielleicht sollte man noch einen Moment warten und dann nochmals prüfen ober der Port immer noch nicht, bzw. das Lockfile immer noch vorhanden ist - danach löschen, oder selbst den Port auf der im lockfile eingetragenen Nummer öffnen.
@EikeB: Ich denke nicht, weil die Existenz der Datei nicht das Starten verhindert, sondern der Lock einer Instanz, wenn die nicht da ist, kann das File auch existieren.