Pregunta

Tengo que evitar que los usuarios iniciar mi aplicación Java (WebStart aplicación Swing) varias veces. Así que si la aplicación ya está en marcha, no debería ser posible ponerla en marcha de nuevo o mostrar una advertencia / cerrarse de nuevo.

¿Hay alguna manera conveniente para lograr esto? Pensé en algo bloqueando un puerto o escribir en un archivo. Pero es de esperar que pueda acceder a algunas propiedades del sistema o la JVM?

por cierto. plataforma de destino es Windows XP con Java 1.5

¿Fue útil?

Solución

Creo que su sugerencia de abrir un puerto para escuchar al iniciar su aplicación es la mejor idea.

Es muy fácil de hacer y usted no tiene que preocuparse de la limpieza para arriba cuando se cierra la aplicación. Por ejemplo, si se escribe en un archivo pero alguien que mata a los procesos que utilizan el Administrador de tareas el archivo no se eliminan.

Además, si no recuerdo mal no existe una manera fácil de obtener el PID de un proceso de Java desde dentro de la JVM por lo que no tratar de formular una solución usando PID.

Algo como esto debe hacer el truco:

private static final int PORT = 9999;
private static ServerSocket socket;    

private static void checkIfRunning() {
  try {
    //Bind to localhost adapter with a zero connection queue 
    socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
  }
  catch (BindException e) {
    System.err.println("Already running.");
    System.exit(1);
  }
  catch (IOException e) {
    System.err.println("Unexpected error.");
    e.printStackTrace();
    System.exit(2);
  }
}

Este código de ejemplo se une explícitamente a 127.0.0.1 que debe evitar cualquier advertencias de firewall, como cualquier tráfico en esta dirección debe ser desde el sistema local.

Al escoger un puerto tratar de evitar que se menciona en la lista de puertos conocidos . Lo ideal es que el puerto utilizado configurable en un archivo o por medio de un interruptor de línea de comandos en caso de conflictos.

Otros consejos

A medida que la pregunta indica que está siendo utilizado WebStart, la solución obvia es utilizar javax.jnlp.SingleInstanceService .

Este servicio está disponible en 1.5. Tenga en cuenta que 1.5 es actualmente la mayor parte del camino a través de su final del período de vida útil. Obtener con Java SE 6!

Creo que la mejor idea sería la de utilizar el bloqueo de archivos (bastante una vieja idea :)). Desde Java 1.4 un nuevo I se introdujo biblioteca E / S, que permite el bloqueo de archivos.

Una vez que se inicia la aplicación que intenta adquirir bloqueo en un archivo (o crearlo si no existe), cuando la aplicación se cierra la cerradura está relased. Si la aplicación no puede obtener un bloqueo, se cierra.

El ejemplo de cómo hacer el bloqueo de archivos es, por ejemplo, en desarrolladores de Java Almanaque .

Si desea utilizar el bloqueo de archivos en la aplicación Java Web Start o un applet que necesita para cantar la aplicación o applet.

Hacemos lo mismo en C ++ mediante la creación de un objeto mutex meollo y buscando que en el arranque. Las ventajas son las mismas que el uso de un enchufe, es decir, cuando el proceso muere / choques / salidas / es matado, el objeto mutex se limpia por el núcleo.

No soy un programador de Java, así que no estoy seguro de si se puede hacer el mismo tipo de cosas en Java?

Puede utilizar la biblioteca JUnique. Proporciona soporte para la ejecución de aplicaciones Java de instancia única y es de código abierto.

http://www.sauronsoftware.it/projects/junique/

Véase también mi respuesta completa en Cómo implementar una aplicación Java sola instancia?

He crear la clase de plataforma cruzada AppLock.

http: //rumatoest.blogspot .com / 2015/01 / howto-gestión única de un solo-java-application.html

Está usando la técnica de bloqueo de archivo.

Actualizar. En 14.10.2016 He creado el paquete compatible con Maven / Gradle https://github.com/jneat/ jneat y explicó aquí http: / /rumatoest.blogspot.com/2015/06/synchronize-code-over-multiple-jvm.html

Se puede utilizar el registro, aunque esta derrota con poco entusiasmo con el propósito de utilizar un lenguaje de alto nivel como Java. Por lo menos la plataforma de destino es ventanas = D

Trate JUnique:

String appId = "com.example.win.run.main";
boolean alreadyRunning;
try {
    JUnique.acquireLock(appId);
    alreadyRunning = false;
} catch (AlreadyLockedException e) {
    alreadyRunning = true;
}
if (alreadyRunning) {
    Sysout("An Instance of this app is already running");
    System.exit(1);
}

He visto que muchos de estas preguntas y yo estaba buscando para resolver el mismo problema de una manera independiente de la plataforma que no tiene la posibilidad de colisionar con los cortafuegos o entrar en materia zócalo.

Por lo tanto, esto es lo que hice:

import java.io.File;
import java.io.IOException;

/**
 * This static class is in charge of file-locking the program
 * so no more than one instance can be run at the same time.
 * @author nirei
 */
public class SingleInstanceLock {

    private static final String LOCK_FILEPATH = System.getProperty("java.io.tmpdir") + File.separator + "lector.lock";
    private static final File lock = new File(LOCK_FILEPATH);
    private static boolean locked = false;

    private SingleInstanceLock() {}

    /**
     * Creates the lock file if it's not present and requests its deletion on
     * program termination or informs that the program is already running if
     * that's the case.
     * @return true - if the operation was succesful or if the program already has the lock.<br>
     * false - if the program is already running
     * @throws IOException if the lock file cannot be created.
     */
    public static boolean lock() throws IOException {
        if(locked) return true;

        if(lock.exists()) return false;

        lock.createNewFile();
        lock.deleteOnExit();
        locked = true;
        return true;
    }
}

El uso de System.getProperty ( "java.io.tmpdir") para la ruta de archivo de bloqueo se asegura de que siempre va a crear su bloqueo en el mismo lugar.

A continuación, a partir de su programa que acaba de llamar algo como:

blah blah main(blah blah blah) {
    try() {
        if(!SingleInstanceLock.lock()) {
            System.out.println("The program is already running");
            System.exit(0);
        }
    } catch (IOException e) {
        System.err.println("Couldn't create lock file or w/e");
        System.exit(1);
    }
}

Y que lo hace por mí. Ahora, si matas el programa no va a borrar el archivo de bloqueo, pero se puede solucionar esto escribiendo el PID del programa en el fichero de bloqueo y hacer que el cheque método de bloqueo () si ese proceso ya está en marcha. Esto se deja como assingment para cualquier persona interesada. :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top