Application einmalig exklusiv starten

Status
Nicht offen für weitere Antworten.
D

Dirk

Gast
Hallo,
ich möchte verhindern, daß eine Anwendung mehrfach zur gleichen Zeit gestartet wird! Wenn ich für meine zentrale Klasse die herkömmliche Singletonimplementierung nehme, dann klappt das leider nicht.

Gibt es dafür eventuell eine Lösung?

Grüße,
Dirk
 

Tobias

Top Contributor
Ich schätze mal, das wird nicht klappen, da die Verwaltung der nebeneinanderlaufenden Anwendungen ja dem Betriebssystem obliegt - und da kann man ja mit Java relativ wenig machen.

mpG
Tobias,
der aber auch noch längst nicht alles weiß.
 
D

Dirk

Gast
Danke für die Antwort Tobias!
Ich habe sowas schon befürchtet. Aber vielleicht gibt es ja doch noch eine Lösung. Zumindest habe ich schon mal von Singletons gelesen, die sowas berücksichtigen. Aber das war eben ohne jede Implementierung.

Gruß,
Dirk
 

René Link

Aktives Mitglied
Hi Dirk,

also mit dem Singleton-Pattern wirst du das niemals schaffen. Das Singleton-Pattern verhindert (bei richtiger Implementierung -- Probleme mit mehrern Threads abfangen -> synchronized) , dass es mehr als eine
Instanz einer Klasse gibt. Wie du ja weißt werden alle Objekte auf dem Heap alloziert. Tja, der Heap
gehört zum Prozess bzw. Zum Adressraum des Prozesses. Wenn du deine Anwendung ein zweites Mal
startest, startest du einen neuen Prozess. Das kannst du ganz leicht mit dem Task-Manager nachvollziehen.

Jeder Prozess hat seinen eigenen virtuellen Adressraum. Die Hardware und das Betriebssystem sorgen
dafür, dass ein Prozess nicht den Speicher eines anderen lesen oder beschreiben kann. Das ist auch
gut so, sonst wäre der Manipulation von Daten ja Tür und Tor weit geöffnet.

Das was du suchst nennt man Interprozesskommunikation. Wau was für ein langes Wort.
Der eine Prozess soll dem anderen mitteilen, dass er schon läuft. Manche Betriebssysteme
bieten soetwas wie einen gemeinsamen Speicherbereich für die Interprozesskommunikation.
Man kann auch mit Pipes arbeiten. Indem man die Ausgabe des einen Prozesses über einen Puffer
in die Eingabe des Anderen umlenkt.

Aber die Lösung für dein Problem ist viel einfacher. Lass deinen Prozess einfach eine Datei an einer
bestimmten Position erstellen. Am besten im Arbeitsverzeichnis. Jeder Prozess prüft erst, ob es die Datei
schon gibt. Wenn es sie schon gibt wird beendet. Du musst jetzt allerdings darauf achten, dass deine
Anwendung die Datei beim Runterfahren wieder entfernt.

Diese Lösung ist noch nicht sehr schön. Also auf ein Neues. In Java gibt es seit JDK 1.4 das Paket
java.nio. Und darin gibt es channels. Aber jetzt mal langsam.

Erstelle einen FileInputStream auf eine beliebige Datei, welche als Synchronisationselement dienen soll.
Danach lässt du dir einen FileChannel vom FileInputStream geben. Das geht mit der getChannel-Methode.
Jetzt sperrst du die Datei exklusiv, indem du auf das FileChannel-Objekt die tryLock-Methode auf.
Wenn dir die ein FileLock-Objekt zurückgibt kann deine Anwendung weitermachen. Aber sicher dir eine
Referen auf das FileLock-Objekt (zum Beispiel private static FileLock lock). Wenn deine Anwendung fertig ist
rufst du einfach release auf dem FileLock-Objekt auf. Startet jetzt jemand einen zweiten Prozess mit deiner
Anwendung, so wird dieser von der tryLock-Methode eine null-Referenz zurückbekommen. Das bedeutet, dass
schon eine Anwendung läuft. Also abbrechen System.exit(1).
Du hast mit dieser Version auch keine Probleme, falls deine Anwendung abschmiert. Denn wenn der Prozess
aus irgendeinem Grund gekillt wird sorgt das Betriebssystem dafür, dass die Dateisperren freigegeben werden. :)

So ich hoffe das hilft weiter...

Und hier gibt es was grundlegendes über Betriebssysteme.
In zirka 2-3 Wochen werde ich, wenn ich mal wieder Zeit habe das Tutorial erweitern.
Mir schwebt ein Kapitel über Speicherverwaltung vor (Paging, Segmentierung usw.)
Also wenn du dann noch interesse hast schau noch mal rein.

http://www.computer-link.de/view.php?docID=1
 

René Link

Aktives Mitglied
Hi Dirk,

ich bin es noch mal. Nimm einen FileOutputStream anstatt einen FileInputStream.
Auf einen lesenden Stream eine exklusiv Sperre zu verhängen macht wenig Sinn.
Na ja, im Eifer des Gefechts passiert so manches.

Bis dann
 
D

Dirk

Gast
Danke René,
deine Lösung ist genau richtig für mein Problem! Funktioniert tadellos. Mit dem allgemeinen Gedanken, eine Datei zu verwenden, hatte ich auch schon gespielt. Aber das war mir dann doch etwas zu sehr Hack. Den entscheidenden Unterschied macht eben die Möglichkeit des Lock aus. Gut das Java das jetzt auch unterstützt, und das jemand so schlau ist, mir das sagen zu können ;-). Man sollte eben nie vergessen, wozu Betriebssysteme eigentlich da sind!

Zum Thema habe ich noch zwei kleine Fragen bezüglich der release() Methode:

1. Wenn ich beim Beenden meiner Anwendung diese Methode nicht verwende, bleibt die Funktionalität die gleiche. Zumindest scheint es so zu sein ?! Gibt dann das Bestriebssystem die Sperre automatisch wieder frei nachdem die Anwendung beendet wurde und die Verwendung der Methode release() ist nur ein sauberer Weg?

2. Ist es ok, wenn ich release() in der überschriebenen finalize() Methode() meiner zentralen Klasse wie folgt aufrufe?

Code:
    public void finalize() {
        lock.release();
    }


Grüße,
Dirk
 

René Link

Aktives Mitglied
Hi Dirk,

die release-Methode brauchst du in diesem Fall nicht explizit aufzurufen. Ich würde es allerdings trotzdem
tun, weil es einfach guter Programmierstil ist und den sollte man nicht verkommen lassen.
Das Betriebsystem gibt alle Dateisperren, die dein Prozess auf irgendwelchen Dateien hat, wieder frei wenn der Prozess
beendet wird. Es gibt ja keinen Grund eine Sperre für jemanden zu erhalten, den es nicht mehr gibt bzw. Ressourcen
zu reservieren. Auch schliesst das Betriebssystem jede noch geöffnete Datei. Da die Ressourcenverwaltung im BS
allerdings Speicherplatz und auch Bearbeitungszeit in Anspruch nimmt, sollte man Ressourcen immer freigeben,
wenn man sie nicht mehr benötigt.

In deinem Fall benötigt dein Programm die Ressource allerdings bis zum Ende. Deshalb wäre es hier egal.
Bleib aber trotzdem beim guten Stil. :lol:

Übrigens ...
Wir Programmieren ja objektorientiert und das bedeutet ja auch Wiederverwendbarkeit von Code wie wäre es
damit.

Code:
import java.io.*;
import java.nio.channels.*;

public class ApplicationRunner {
  
  public static void main(String[] args) {
    try {
      // 1. Argument ist der volle Klassenname z.B. myPackage.myApp.MyApplication
      Class clazz = Class.forName(args[0]);
      Application app = (Application) clazz.newInstance();
      String[] appArgs = new String[args.length-1];
      
      // Argumente ohne Klassennamen an die Application weiterreichen.
      System.arraycopy(args, 1, appArgs, 0, appArgs.length);
      
      // LockFile erstellen und Stream anfordern.
      File lockFile = File.createTempFile(clazz.getName(), ".lock");
      lockFile.deleteOnExit();
      FileOutputStream outLock = new FileOutputStream(lockFile);
      
      // lock anfordern
      FileLock lock = outLock.getChannel().tryLock();
      if(lock == null){ // lock Anforderung fehlgeschlagen -> Anwendung läuft bereits.
        System.out.println("Lock file can not be created. System exits now.");
        System.exit(1);
      }
      
      // application starten
      int returnCode = app.run(appArgs);
      
      // lock freigeben, Stream schließen und beenden
      lock.release();
      outLock.close();
      System.exit(returnCode);
    }
    catch (Exception ex) {
      // Bei irgendeinem Fehler abbrechen.
      System.out.println(ex);
    }
  }
}

//========================================================

public abstract class Application {

  private boolean run = true;
  private int returnCode;
  protected String[] args;

  public abstract void init();
  public abstract void idle();
  public abstract void cleanUp();

  public final int run(String args[]) {
    this.args = args;
    init();
    while (run) {
      try{
        idle();
      } catch( RuntimeException e){
        System.out.println(e);
        exit(1);
      }
    }
    cleanUp();
    return returnCode;
  }

  public final void exit(int returnCode) {
    this.returnCode = returnCode;
    this.run = false;
  }
}

class MyApplication extends Application {
  private int i;
  public void init() {
    System.out.println("init ...");
  }

  public void idle() {
    System.out.println("I'm running ...");
    exit(0);
  }

  public void cleanUp() {
    System.out.println("cleanUp ...");
  }
}

Über den Code kannst du ja mal ein wenig nachdenken.
Wenn du dir diese Klassen allerdings einmal erstellt hast, kannst du auf die Funktionalität immer wieder
zurückgreifen. :D Du musst wenn du eine neue Applikation schreiben willst, die exklusiv laufen soll, nur
von Application ableiten die Methoden idle, init und cleanUp überschreiben und anschließend die Klasse dem ApplicationRunner
als Argument übergeben.
Also beispielsweise so:

java myPackage.ApplicationRunner myPackage.MyApplication Irgendwelche Argumente
 

René Link

Aktives Mitglied
Hi nochmal,

jetzt habe ich ganz vergessen, deine 2. Frage zu beantworten.

Du kannst das machen. Allerdings musst du dann irgendwo (am bestem in main(..) ) die
runFinalizersOnExit-Methode aufgerufen haben.

Also

Code:
System.runFinalizersOnExit();

Allerdings gibt es mit dieser Methode ein paar Probleme mit Threads und dadurch entstehenden
Deadlock-Situationen. Deshalb ist die Methode auch als deprecated gekennzeichnet. Lies das am besten in der Javadoc nach.
 
D

Dirk

Gast
Nochmals vielen Dank für die Beantwortung meiner Fragen Renè! Der Code sieht auch ziemlich praktisch aus. Wenn ich wieder mal sowas benötige, werde ich wohl darauf zurückgreifen.

Grüße,
Dirk
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Integration pay Pale in eine JavaFx Desktop Application Allgemeine Java-Themen 1
B JAX - RS.... Multiple parameter application/x-www-form-urlencoded.... Allgemeine Java-Themen 6
M this application requires a java runtime environment 1.8.0 Allgemeine Java-Themen 2
Tommy135 Input/Output Application aus Java package starten Allgemeine Java-Themen 2
P Am Application Server - Selbe files aber trotzdem CNF Allgemeine Java-Themen 2
J Application mit PLugin erweitern Allgemeine Java-Themen 2
A JWS application - log4j wie configurieren Allgemeine Java-Themen 1
T Tabletkamera per Java Application ansteuern Allgemeine Java-Themen 1
T Erste Schritte FAIL - Deployed application at context path / but context failed to start Allgemeine Java-Themen 1
I JRE mit Application ausliefern Allgemeine Java-Themen 12
C Can't start application since jvm.dll is not installed Allgemeine Java-Themen 1
D Best Practice Java Application Server , Docker oder was? Allgemeine Java-Themen 15
B Exception in Application init method Allgemeine Java-Themen 5
RalleYTN REST API ResponseType application/pdf lesen Allgemeine Java-Themen 0
C Windows RCP Application unter Linux bauen lassen Allgemeine Java-Themen 3
F Best Practice Application extern nur einmal startbar Allgemeine Java-Themen 3
C Unterschiedliches Verhalten Editor und deployte Application Allgemeine Java-Themen 3
N Input/Output SEO-autoTest Application Allgemeine Java-Themen 4
B A newer version of Java is needed to view the application. Allgemeine Java-Themen 17
E Application -> Applet Allgemeine Java-Themen 9
J Application Server Allgemeine Java-Themen 2
T Java Application zu Applet Allgemeine Java-Themen 4
C Java Application und OpenOffice Allgemeine Java-Themen 5
V plugin.jar in application aus jar Allgemeine Java-Themen 2
Fadi Java Application mit Plugnis erweiteren Allgemeine Java-Themen 4
J Java Application auf 2 Monitore Allgemeine Java-Themen 2
G java application stub / fehler Allgemeine Java-Themen 2
M IRC Chat - Klasse oder Application gesucht Allgemeine Java-Themen 9
T Executable Java-Application erstellen Allgemeine Java-Themen 2
T PIMP my Application Allgemeine Java-Themen 19
R Drag und Drop von externen Files geht nur als Application Allgemeine Java-Themen 2
P Java - Application auf Debian System zum laufen bringen Allgemeine Java-Themen 11
P java application in das rechtsklick menü im explorer adden? Allgemeine Java-Themen 21
N Datei mit Java-Application öffenen Allgemeine Java-Themen 5
sambalmueslie "Selbstlaufende" Application Allgemeine Java-Themen 2
S HTML Seitenaufruf aus einer Java Application Allgemeine Java-Themen 5
S Java Application Installieren - von CD Autostarten Allgemeine Java-Themen 7
H Application Shut Down. Allgemeine Java-Themen 15
T Java Application Server + Datenbank von CD Allgemeine Java-Themen 8
juppi Java-plug-in mit Application ansteuern Allgemeine Java-Themen 2
M von der application zur einfachen java-anwendung Allgemeine Java-Themen 4
C Java Anwendung nur einmalig starten Allgemeine Java-Themen 10

Ähnliche Java Themen

Neue Themen


Oben